Self-hosting
Run the service and its documentation from the same Vercel project.
Run locally
git clone https://github.com/pc-style/x-md.git
cd x-md
bun install
bun run dev
The Vite server runs the landing page and local API handlers. Run bun run docs:dev separately for the Blume documentation server.
Build and deploy
bun run build
vercel --prod
The build generates Blume docs, then the Vite landing page into dist. The included Vercel configuration serves /docs, the static assets, and the API rewrites together.
- docs/
- index.mdx
- (api)/
- posts.mdx
- search.mdx
- profiles.mdx
- pagination.mdx
- responses.mdx
- reliability.mdx
- meta.ts
- agents.mdx
- self-hosting.mdx
- blume.config.ts
- theme.css
Live search provider
Latest and Top try FxTwitter, then the custom-built live search provider, then an optional Firecrawl web fallback. Photos, Videos, and Users use the live provider directly and return 503 when it is not configured.
The provider is configured through X_SEARCH_SESSIONS_JSON; the expected shape is defined in lib/xsearch.ts. For local development, use the gitignored accounts.local.json. Treat its contents as secrets and keep them out of version control.
The provider budgets its own upstream capacity per 15-minute window, shared across post and user searches. Failed attempts and page walks count. Unhealthy entries are taken out of rotation in the current process and retried later; health is per instance.
Shared counters
Attach Upstash Redis through the Vercel marketplace or CLI. The service automatically uses either environment-variable pair:
KV_REST_API_URLandKV_REST_API_TOKENUPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN
These share per-IP and provider counters across instances. Without them, counters fall back to process memory. Live-provider checks fail closed when the counter store is unavailable, protecting the shared pool; the general request limiter still fails open. Redeploy after connecting environment variables.
Historical statistics
PostHog is optional. Connect its Vercel Marketplace integration to the production environment, choose your data region, and review its billing terms. It supplies NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN and NEXT_PUBLIC_POSTHOG_HOST; the API reads these on the server only. Alternatively, set POSTHOG_PROJECT_TOKEN and POSTHOG_HOST (for example, https://eu.i.posthog.com). Redeploy after configuring them.
Production API functions send a request_completed event with the route category, method, HTTP status, duration in milliseconds, application-cache result, key-validation status, public/key access, and degraded-search flag. Use these for request volume by endpoint, error and 429 rates, latency percentiles, and application-cache hit rate. Delivery runs in the background with a three-second timeout; failures do not change API responses.
request_completed events contain no search text, URLs, client IPs, bearer tokens, or key labels. Verified keys use a pseudonymous ID derived from their internal ID and the PostHog project token; rotating that token changes the pseudonyms. Public requests have a new ID per event, so distinct-user counts and anonymous retention are not meaningful. Person profiles, geolocation enrichment, and session replay are not enabled by this instrumentation.
These statistics cover completed function responses, not requests served by Vercel’s CDN, aborted requests, or platform errors before the handler runs. They are not billing-grade totals. Local development, previews, admin routes, and CORS preflights are excluded. Redis remains the source of truth for live limits and capacity; PostHog is only for historical analysis.
Landing-page web analytics
Set VITE_POSTHOG_KEY to the project token and VITE_POSTHOG_HOST to its ingestion host or managed reverse proxy (this deployment uses https://p.pcstyle.dev). These are public build-time values, not personal API credentials. Rebuild after changing them. Capture requires a production build with VERCEL_ENV=production; local development and previews do not send events. The SDK’s ui_host points to EU PostHog. In PostHog’s Web Analytics settings, add your public site URL (for this deployment, https://x.pcstyle.dev).
The landing page sends pageviews, page leaves, conversion_requested, and skill_install_command_copied. Anonymous browser IDs persist in local storage to measure returning visitors; session and browser/device properties support Web Analytics. No person profiles are created. Event URLs contain only the landing-page origin and /, without query strings or fragments. Referrers, form contents, automatic clicks, errors, and recordings are excluded; traffic-source attribution and geographic reports are therefore limited. The proxy receives the browser’s source IP, while event properties disable IP-based enrichment.
This covers the landing page only, not docs, converted posts, or admin. API events remain separate from browser visits. Existing Vercel Web Analytics on the public landing page is unchanged. The admin dashboard includes no analytics scripts.
Optional configuration
| Variable | Purpose |
|---|---|
FIRECRAWL_API_KEY |
Conversion fallback and degraded Latest/Top search |
CONTEXT_DEV_API_KEY |
Additional post-conversion fallback |
CACHE_TTL_SECONDS |
Cache lifetime; default 3600 |
CACHE_DISABLED |
Disable application caching |
CACHE_PERSIST |
Control persistent application caching |