@prmichaelsen/acp-visualizer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +68 -0
  2. package/agent/commands/acp.clarification-address.md +417 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +437 -0
  5. package/agent/commands/acp.clarifications-research.md +326 -0
  6. package/agent/commands/acp.command-create.md +432 -0
  7. package/agent/commands/acp.design-create.md +286 -0
  8. package/agent/commands/acp.design-reference.md +355 -0
  9. package/agent/commands/acp.handoff.md +270 -0
  10. package/agent/commands/acp.index.md +423 -0
  11. package/agent/commands/acp.init.md +546 -0
  12. package/agent/commands/acp.package-create.md +895 -0
  13. package/agent/commands/acp.package-info.md +212 -0
  14. package/agent/commands/acp.package-install.md +539 -0
  15. package/agent/commands/acp.package-list.md +280 -0
  16. package/agent/commands/acp.package-publish.md +541 -0
  17. package/agent/commands/acp.package-remove.md +293 -0
  18. package/agent/commands/acp.package-search.md +307 -0
  19. package/agent/commands/acp.package-update.md +361 -0
  20. package/agent/commands/acp.package-validate.md +540 -0
  21. package/agent/commands/acp.pattern-create.md +386 -0
  22. package/agent/commands/acp.plan.md +587 -0
  23. package/agent/commands/acp.proceed.md +882 -0
  24. package/agent/commands/acp.project-create.md +675 -0
  25. package/agent/commands/acp.project-info.md +312 -0
  26. package/agent/commands/acp.project-list.md +226 -0
  27. package/agent/commands/acp.project-remove.md +379 -0
  28. package/agent/commands/acp.project-set.md +227 -0
  29. package/agent/commands/acp.project-update.md +307 -0
  30. package/agent/commands/acp.projects-restore.md +228 -0
  31. package/agent/commands/acp.projects-sync.md +347 -0
  32. package/agent/commands/acp.report.md +407 -0
  33. package/agent/commands/acp.resume.md +239 -0
  34. package/agent/commands/acp.sessions.md +301 -0
  35. package/agent/commands/acp.status.md +293 -0
  36. package/agent/commands/acp.sync.md +364 -0
  37. package/agent/commands/acp.task-create.md +500 -0
  38. package/agent/commands/acp.update.md +302 -0
  39. package/agent/commands/acp.validate.md +466 -0
  40. package/agent/commands/acp.version-check-for-updates.md +276 -0
  41. package/agent/commands/acp.version-check.md +191 -0
  42. package/agent/commands/acp.version-update.md +289 -0
  43. package/agent/commands/command.template.md +339 -0
  44. package/agent/commands/git.commit.md +526 -0
  45. package/agent/commands/git.init.md +514 -0
  46. package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
  47. package/agent/commands/tanstack-cloudflare.tail.md +275 -0
  48. package/agent/design/.gitkeep +0 -0
  49. package/agent/design/design.template.md +154 -0
  50. package/agent/design/local.dashboard-layout-routing.md +288 -0
  51. package/agent/design/local.data-model-yaml-parsing.md +310 -0
  52. package/agent/design/local.search-filtering.md +331 -0
  53. package/agent/design/local.server-api-auto-refresh.md +235 -0
  54. package/agent/design/local.table-tree-views.md +299 -0
  55. package/agent/design/local.visualizer-requirements.md +349 -0
  56. package/agent/design/requirements.template.md +387 -0
  57. package/agent/index/.gitkeep +0 -0
  58. package/agent/index/acp.core.yaml +137 -0
  59. package/agent/index/local.main.template.yaml +37 -0
  60. package/agent/manifest.template.yaml +13 -0
  61. package/agent/manifest.yaml +302 -0
  62. package/agent/milestones/.gitkeep +0 -0
  63. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
  64. package/agent/milestones/milestone-1-{title}.template.md +206 -0
  65. package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
  66. package/agent/package.template.yaml +86 -0
  67. package/agent/patterns/.gitkeep +0 -0
  68. package/agent/patterns/bootstrap.template.md +1237 -0
  69. package/agent/patterns/pattern.template.md +382 -0
  70. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
  71. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
  72. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
  73. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
  74. package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
  75. package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
  76. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
  77. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
  78. package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
  79. package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
  80. package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
  81. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
  82. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
  83. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
  84. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
  85. package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
  86. package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
  87. package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
  88. package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
  89. package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
  90. package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
  91. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
  92. package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
  93. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
  94. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
  95. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
  96. package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
  97. package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
  98. package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
  99. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
  100. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
  101. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
  102. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
  103. package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
  104. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
  105. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
  106. package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
  107. package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
  108. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
  109. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
  110. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
  111. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
  112. package/agent/progress.template.yaml +161 -0
  113. package/agent/progress.yaml +145 -0
  114. package/agent/schemas/package.schema.yaml +276 -0
  115. package/agent/scripts/acp.common.sh +1781 -0
  116. package/agent/scripts/acp.install.sh +333 -0
  117. package/agent/scripts/acp.package-create.sh +924 -0
  118. package/agent/scripts/acp.package-info.sh +288 -0
  119. package/agent/scripts/acp.package-install.sh +893 -0
  120. package/agent/scripts/acp.package-list.sh +311 -0
  121. package/agent/scripts/acp.package-publish.sh +420 -0
  122. package/agent/scripts/acp.package-remove.sh +348 -0
  123. package/agent/scripts/acp.package-search.sh +156 -0
  124. package/agent/scripts/acp.package-update.sh +517 -0
  125. package/agent/scripts/acp.package-validate.sh +1018 -0
  126. package/agent/scripts/acp.uninstall.sh +85 -0
  127. package/agent/scripts/acp.version-check-for-updates.sh +98 -0
  128. package/agent/scripts/acp.version-check.sh +47 -0
  129. package/agent/scripts/acp.version-update.sh +176 -0
  130. package/agent/scripts/acp.yaml-parser.sh +985 -0
  131. package/agent/scripts/acp.yaml-validate.sh +205 -0
  132. package/agent/tasks/.gitkeep +0 -0
  133. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
  134. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
  135. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
  136. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
  137. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
  138. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
  139. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
  140. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
  141. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
  142. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
  143. package/agent/tasks/task-1-{title}.template.md +244 -0
  144. package/bin/visualize.mjs +84 -0
  145. package/package.json +48 -0
  146. package/src/components/ExtraFieldsBadge.tsx +15 -0
  147. package/src/components/FilterBar.tsx +33 -0
  148. package/src/components/Header.tsx +23 -0
  149. package/src/components/MilestoneTable.tsx +167 -0
  150. package/src/components/MilestoneTree.tsx +84 -0
  151. package/src/components/ProgressBar.tsx +20 -0
  152. package/src/components/SearchInput.tsx +22 -0
  153. package/src/components/Sidebar.tsx +54 -0
  154. package/src/components/StatusBadge.tsx +23 -0
  155. package/src/components/StatusDot.tsx +12 -0
  156. package/src/components/TaskList.tsx +36 -0
  157. package/src/components/ViewToggle.tsx +31 -0
  158. package/src/lib/config.ts +8 -0
  159. package/src/lib/file-watcher.ts +43 -0
  160. package/src/lib/search.ts +48 -0
  161. package/src/lib/types.ts +73 -0
  162. package/src/lib/useAutoRefresh.ts +31 -0
  163. package/src/lib/useCollapse.ts +31 -0
  164. package/src/lib/useFilteredData.ts +55 -0
  165. package/src/lib/yaml-loader-real.spec.ts +47 -0
  166. package/src/lib/yaml-loader.spec.ts +201 -0
  167. package/src/lib/yaml-loader.ts +265 -0
  168. package/src/routeTree.gen.ts +140 -0
  169. package/src/router.tsx +10 -0
  170. package/src/routes/__root.tsx +75 -0
  171. package/src/routes/api/watch.ts +29 -0
  172. package/src/routes/index.tsx +115 -0
  173. package/src/routes/milestones.tsx +50 -0
  174. package/src/routes/search.tsx +84 -0
  175. package/src/routes/tasks.tsx +63 -0
  176. package/src/services/progress-database.service.ts +46 -0
  177. package/src/styles.css +25 -0
  178. package/tsconfig.json +24 -0
  179. package/vite.config.ts +16 -0
  180. package/vitest.config.ts +27 -0
@@ -0,0 +1,296 @@
1
+ # OG Metadata Pattern
2
+
3
+ **Category**: Code
4
+ **Applicable To**: TanStack Start routes that need social media link previews (Open Graph + Twitter Cards)
5
+ **Status**: Stable
6
+
7
+ ---
8
+
9
+ ## Overview
10
+
11
+ Every route that can be shared on social media (iMessage, Slack, Discord, Twitter/X, Facebook) needs server-rendered Open Graph and Twitter Card meta tags in the HTML `<head>`. TanStack Start provides a `head()` function on route definitions that runs during SSR — this is the only mechanism that works for social crawlers, which do not execute JavaScript.
12
+
13
+ This pattern documents how to add OG metadata to routes, covering static pages, dynamic content pages with SSR loader data, and the global defaults that all routes inherit.
14
+
15
+ ---
16
+
17
+ ## When to Use This Pattern
18
+
19
+ **Use this pattern when:**
20
+ - Adding a new route that users might share (link previews)
21
+ - Adding SSR data to a route that already has OG tags
22
+ - Creating shareable content pages (memories, profiles, invite links)
23
+ - Debugging why a shared link shows the wrong preview
24
+
25
+ **Don't use this pattern when:**
26
+ - The route is behind authentication with no public preview needed
27
+ - The route is an API endpoint (`/api/*`)
28
+
29
+ ---
30
+
31
+ ## Core Principles
32
+
33
+ 1. **SSR-Only**: Social crawlers don't run JS — `head()` runs server-side so tags appear in the initial HTML response
34
+ 2. **Route-Level Overrides**: Child route `head()` tags override parent (root) defaults by property
35
+ 3. **Graceful Fallback**: If loader data fails, return generic site-level OG tags — never render a page with no OG
36
+ 4. **Auth After Meta**: For shareable links (invite codes), check auth in the component, not `beforeLoad`, so crawlers see meta tags without being redirected
37
+
38
+ ---
39
+
40
+ ## Implementation
41
+
42
+ ### Global Defaults (Root Route)
43
+
44
+ `src/routes/__root.tsx` defines site-wide fallback OG tags via `createRootRoute({ head() })`:
45
+
46
+ ```typescript
47
+ export const Route = createRootRoute({
48
+ head: () => ({
49
+ meta: [
50
+ { charSet: 'utf-8' },
51
+ { name: 'viewport', content: 'width=device-width, initial-scale=1, ...' },
52
+ { title: 'agentbase — social AI with memory, ghosts, and shared spaces' },
53
+ { name: 'description', content: 'A social AI platform with persistent memory...' },
54
+ { property: 'og:type', content: 'website' },
55
+ { property: 'og:site_name', content: 'agentbase' },
56
+ { property: 'og:title', content: 'agentbase — social AI with memory, ghosts, and shared spaces' },
57
+ { property: 'og:description', content: 'A social AI platform with persistent memory...' },
58
+ { property: 'og:image', content: 'https://agentbase.me/icon-512x512.png' },
59
+ { name: 'twitter:card', content: 'summary_large_image' },
60
+ { name: 'twitter:title', content: 'agentbase — ...' },
61
+ { name: 'twitter:description', content: '...' },
62
+ { name: 'twitter:image', content: 'https://agentbase.me/icon-512x512.png' },
63
+ ],
64
+ }),
65
+ component: RootComponent,
66
+ })
67
+ ```
68
+
69
+ The root also renders `<HeadContent />` inside `<head>` to inject these tags into the HTML.
70
+
71
+ ### Static Page OG
72
+
73
+ For pages with fixed content (terms, privacy, homepage, invite links):
74
+
75
+ ```typescript
76
+ export const Route = createFileRoute('/terms')({
77
+ head: () => ({
78
+ meta: [
79
+ { title: 'Terms of Service — agentbase' },
80
+ { name: 'description', content: 'Terms of service for agentbase.' },
81
+ { property: 'og:title', content: 'Terms of Service — agentbase' },
82
+ { property: 'og:description', content: 'Terms of service for agentbase.' },
83
+ { property: 'og:type', content: 'website' },
84
+ { property: 'og:site_name', content: 'agentbase' },
85
+ { property: 'og:image', content: 'https://agentbase.me/icon-512x512.png' },
86
+ { name: 'twitter:card', content: 'summary' },
87
+ { name: 'twitter:title', content: 'Terms of Service — agentbase' },
88
+ { name: 'twitter:description', content: 'Terms of service for agentbase.' },
89
+ { name: 'twitter:image', content: 'https://agentbase.me/icon-512x512.png' },
90
+ ],
91
+ }),
92
+ component: TermsPage,
93
+ })
94
+ ```
95
+
96
+ ### Dynamic Content OG (SSR Loader)
97
+
98
+ For pages where OG tags depend on data (memory detail, profile), use `createServerFn` + `loader` + `head(loaderData)`:
99
+
100
+ ```typescript
101
+ // 1. Server function fetches data during SSR
102
+ const fetchMemoryDetail = createServerFn({ method: 'GET' })
103
+ .inputValidator((data: { memoryId: string }) => data)
104
+ .handler(async ({ data }) => {
105
+ // Fetch memory from backend
106
+ const memory = await svc.memories.get(userId, data.memoryId)
107
+ return { memory }
108
+ })
109
+
110
+ // 2. Route loader calls server function
111
+ export const Route = createFileRoute('/memories/$memoryId')({
112
+ loader: async ({ params }) => {
113
+ const memoryData = await fetchMemoryDetail({ data: { memoryId: params.memoryId } })
114
+ return { memoryData }
115
+ },
116
+
117
+ // 3. head() receives loader data and generates dynamic tags
118
+ head: (({ loaderData }: any) => {
119
+ const memory = loaderData?.memoryData?.memory
120
+ if (!memory) {
121
+ return {
122
+ meta: [
123
+ { title: 'Memory — agentbase' },
124
+ { property: 'og:title', content: 'Memory — agentbase' },
125
+ { property: 'og:image', content: 'https://agentbase.me/icon-512x512.png' },
126
+ // ... fallback tags
127
+ ],
128
+ }
129
+ }
130
+
131
+ const rawTitle = memory.title || memory.content?.split('\n')[0] || 'Memory'
132
+ const title = rawTitle.length > 60 ? rawTitle.substring(0, 57) + '...' : rawTitle
133
+ const description = (memory.content ?? '').substring(0, 200)
134
+
135
+ return {
136
+ meta: [
137
+ { title: `${title} — agentbase` },
138
+ { name: 'description', content: description },
139
+ { property: 'og:title', content: title },
140
+ { property: 'og:description', content: description },
141
+ { property: 'og:type', content: 'article' },
142
+ { property: 'og:site_name', content: 'agentbase' },
143
+ { property: 'og:image', content: 'https://agentbase.me/icon-512x512.png' },
144
+ { name: 'twitter:card', content: 'summary' },
145
+ { name: 'twitter:title', content: title },
146
+ { name: 'twitter:description', content: description },
147
+ { name: 'twitter:image', content: 'https://agentbase.me/icon-512x512.png' },
148
+ ],
149
+ }
150
+ }) as any,
151
+
152
+ component: MemoryDetailPage,
153
+ })
154
+ ```
155
+
156
+ ### Dynamic OG Image (Profile Pages)
157
+
158
+ Profile pages use the `/api/storage/image` proxy to serve user-uploaded profile pictures as OG images:
159
+
160
+ ```typescript
161
+ head: (({ loaderData }: any) => {
162
+ const profile = loaderData?.profileForHead
163
+ if (profile && profile.is_published) {
164
+ const image = profile.profile_picture_path
165
+ ? `https://agentbase.me/api/storage/image?path=${encodeURIComponent(profile.profile_picture_path)}&context=profile`
166
+ : 'https://agentbase.me/icon-512x512.png'
167
+
168
+ return {
169
+ meta: [
170
+ { property: 'og:image', content: image },
171
+ { name: 'twitter:image', content: image },
172
+ // ... other tags
173
+ ],
174
+ }
175
+ }
176
+ // fallback for unpublished profiles
177
+ }) as any
178
+ ```
179
+
180
+ ### Shareable Invite Links (Auth After Meta)
181
+
182
+ For pages like `/friend-links/$code`, `/group-links/$code`, `/dm-links/$code` — use **static OG** and defer auth to the component:
183
+
184
+ ```typescript
185
+ export const Route = createFileRoute('/friend-links/$code')({
186
+ // Static head — no loader needed, crawlers see this immediately
187
+ head: () => ({
188
+ meta: [
189
+ { title: 'Friend Invite — agentbase' },
190
+ { property: 'og:title', content: 'Friend Invite — agentbase' },
191
+ { property: 'og:description', content: "You've been invited to connect on agentbase." },
192
+ // ...
193
+ ],
194
+ }),
195
+ // Auth check happens HERE, not in beforeLoad — crawlers never hit this
196
+ component: FriendLinkPage,
197
+ })
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Required Meta Tags Checklist
203
+
204
+ Every route with OG metadata should include all of these:
205
+
206
+ | Tag | Property | Notes |
207
+ |-----|----------|-------|
208
+ | `<title>` | `{ title: '...' }` | Browser tab title |
209
+ | `description` | `{ name: 'description', content: '...' }` | Search engine description |
210
+ | `og:title` | `{ property: 'og:title', content: '...' }` | Social card title |
211
+ | `og:description` | `{ property: 'og:description', content: '...' }` | Social card description |
212
+ | `og:type` | `{ property: 'og:type', content: '...' }` | `website` or `article` |
213
+ | `og:site_name` | `{ property: 'og:site_name', content: 'agentbase' }` | Always `agentbase` |
214
+ | `og:image` | `{ property: 'og:image', content: '...' }` | Absolute URL, min 200x200 |
215
+ | `twitter:card` | `{ name: 'twitter:card', content: '...' }` | `summary` or `summary_large_image` |
216
+ | `twitter:title` | `{ name: 'twitter:title', content: '...' }` | Same as `og:title` |
217
+ | `twitter:description` | `{ name: 'twitter:description', content: '...' }` | Same as `og:description` |
218
+ | `twitter:image` | `{ name: 'twitter:image', content: '...' }` | Same as `og:image` |
219
+
220
+ ---
221
+
222
+ ## OG Type Reference
223
+
224
+ | Route Type | `og:type` | `twitter:card` |
225
+ |------------|-----------|----------------|
226
+ | Homepage / static pages | `website` | `summary_large_image` |
227
+ | Memory detail | `article` | `summary` |
228
+ | Profile page | `profile` | `summary` |
229
+ | Space / group pages | `website` | `summary` |
230
+ | Invite links | `website` | `summary` |
231
+
232
+ ---
233
+
234
+ ## Anti-Patterns
235
+
236
+ ### Auth in beforeLoad for shareable pages
237
+
238
+ **Description**: Redirecting unauthenticated users in `beforeLoad` before `head()` runs.
239
+
240
+ **Why it's bad**: Social crawlers are unauthenticated — they get redirected to login and never see OG tags.
241
+
242
+ **Instead**: Check auth in the component, not `beforeLoad`. The `head()` function runs regardless.
243
+
244
+ ### Missing fallback when loader fails
245
+
246
+ **Description**: Not handling the case where `loaderData` is undefined in `head()`.
247
+
248
+ **Why it's bad**: A failed fetch produces a page with no OG tags — shared links show a blank preview.
249
+
250
+ **Instead**: Always return fallback OG tags when data is missing.
251
+
252
+ ### Relative OG image URLs
253
+
254
+ **Description**: Using `/icon-512x512.png` instead of `https://agentbase.me/icon-512x512.png`.
255
+
256
+ **Why it's bad**: Some social crawlers don't resolve relative URLs.
257
+
258
+ **Instead**: Always use absolute URLs for `og:image` and `twitter:image`.
259
+
260
+ ---
261
+
262
+ ## Implementation References
263
+
264
+ - **Root defaults**: `src/routes/__root.tsx` (lines 56-108)
265
+ - **Memory detail (dynamic)**: `src/routes/memories/$memoryId.tsx` (lines 131-160)
266
+ - **Profile (dynamic image)**: `src/routes/profile/$userId.tsx` (lines 90-127)
267
+ - **Spaces (conditional image)**: `src/routes/spaces/$spaceId.tsx` (lines 41-53)
268
+ - **Invite links (static, auth-deferred)**: `src/routes/friend-links/$code.tsx` (lines 15-29)
269
+ - **Image proxy**: `src/routes/api/storage/image.tsx`
270
+ - **Static assets**: `public/icon-512x512.png`, `public/the_void_02-512.png`
271
+
272
+ ## Related Patterns
273
+
274
+ - **[SSR Preload](./ssr-preload.md)**: Server-side data loading that feeds into `head()` for dynamic OG
275
+ - **[Firebase Auth](./tanstack-cloudflare.firebase-auth.md)**: Auth patterns — important to understand which routes gate auth in `beforeLoad` vs component
276
+ - **[Firebase Storage](./tanstack-cloudflare.firebase-storage.md)**: Image proxy endpoint used for dynamic OG images
277
+
278
+ ---
279
+
280
+ ## Checklist for Implementation
281
+
282
+ - [ ] `head()` function defined on route with all required meta tags
283
+ - [ ] `og:image` and `twitter:image` use absolute URLs
284
+ - [ ] Dynamic pages have server function + loader feeding `head(loaderData)`
285
+ - [ ] `head()` handles missing/failed loader data with fallback tags
286
+ - [ ] Shareable pages defer auth to component (not `beforeLoad`)
287
+ - [ ] Title truncated to 60 chars max, description to 200 chars max
288
+ - [ ] `og:type` is appropriate (`website` vs `article` vs `profile`)
289
+ - [ ] `og:site_name` is `agentbase`
290
+
291
+ ---
292
+
293
+ **Status**: Stable
294
+ **Recommendation**: Follow this pattern for every new route. Verify OG tags by pasting the URL into the Twitter Card Validator or Facebook Sharing Debugger.
295
+ **Last Updated**: 2026-03-14
296
+ **Contributors**: Community