URL: https://beta.mirascope.com
This is a TypeScript / React / Vite / TanStack Router project that creates the Mirascope website. It auto-deploys to Cloudflare for every pull request, and has thorough CI.
This project uses Bun - a fast all-in-one JavaScript runtime and toolkit.
# Install dependencies
bun install
# Start development server
bun run start
This project is mostly Typescript/React/etc (as stated above). However, there is a small amount of Python code:
- In the public/examples directory. This includes example Python code which is incorporated into the documentation, and typechecked for safety.
- In the public/extracted-snippets directory. This includes example Python code that is automatically extracted from the mdx content, and is typechecked for safety. This should not be edited by hand.
- In the scripts/apigen module, which contains custom Python code for generating API docs for mirascope/mirascope and other libraries.
bun run start [port]
- Start development serverbun run build
- Build for productionbun run serve
- Preview production buildbun run typecheck
- Check typescriptbun test
- Run tests with Bun's built-in Jest-compatible test runnerbun run lint
- All lint checksbun run fix
- All automated fixes (e.g. running prettier)
bun run lint:mdx
- Validate MDX filesbun run lint:social
- Check if generated social cards (OG images) are up to datebun run generate-social
- Update generated social cards and metadatabun run lint:snippets
- Validate code snippets (update check and type/style checking)bun run lint:python
- Run typechecking and linting on the apigen module onlybun run lint:format
- Check formatting with Prettierbun run fix:format
- Format all files with Prettierbun run fix:snippets
- Update extractable code snippetsbun run fix:python
- Fix Python code in the scripts/apigen module
This project uses husky and lint-staged to automatically:
- Format staged files with Prettier
- Validate MDX files
- Check if code snippets are up-to-date
- Run TypeScript type checking
These checks run automatically when you attempt to commit changes, helping maintain code quality and consistency.
This project uses Bun's built-in test runner, which offers Jest-compatible APIs and fast performance. Tests are located in files with .test.ts
extensions throughout the codebase.
To run tests:
# Run all tests
bun test
# Run tests for specific files
bun test ./src/lib/redirects.test.ts
# Run tests with watch mode
bun test --watch
The website uses a unified content management system for handling docs, blog posts, and policy pages. This system provides:
- MDX content processing with frontmatter
- Consistent content loading across development and production
- Typed metadata for each content type
- Error handling and caching
- Document structure specification for documentation
For a detailed overview of the content system architecture, please see Content System Design. This document covers:
- The content loading pipeline and data flow
- File structure and key components
- Type definitions and interfaces
- Error handling strategy
- Common tasks such as adding new content
The documentation contains Python code snippets that are automatically extracted to create runnable example files. These examples are stored in the repository and verified by CI to ensure they stay in sync with the documentation.
- In
content/docs/_meta.ts
, docs with extractable snippets are marked withhasExtractableSnippets: true
- The extraction system pulls Python code blocks from these MDX files
- For each provider (OpenAI, Anthropic), it generates runnable example files with substituted variables
- Examples are stored in
public/extracted-snippets/
with an organized directory structure
bun run fix:snippets
- Update all extractable snippets for all providersbun run lint:snippets
- Check if snippets are up-to-date- You can also use the original script with more options:
bun run scripts/update-snippets.ts --path=<file-path>
- Update snippets for a specific filebun run scripts/update-snippets.ts --check --path=<file-path>
- Check if snippets for a specific file are up-to-datebun run scripts/update-snippets.ts --help
- View all available options
For code blocks that represent partial snippets (not meant to be valid on their own), use the python-no-extract
language tag instead of python
:
> ```python-no-extract
> @app.receiver("audio")
> async def receive_audio(response: AudioSegment, context: dict[str, Any]) -> None:
> play(response)
> ```
This prevents these partial examples from being extracted as standalone snippets and avoids validation errors for code that's missing imports or context. The syntax highlighting still works correctly in the rendered documentation.
Our CI workflow automatically verifies that all code is properly formatted, type-checked, and that extracted snippets are up-to-date with the source documentation. If you modify MDX files with code snippets, make sure to run bun run fix
before committing to update all snippets and formatting.
The og social cards (preview images for each route) are pre-generated and checked in at public/social-cards
, rather than running on build, so as to save time. If you add a new route (e.g. a new blog post), you'll need to generate a new social card. You can use bun run generate-social --update
for this purpose. CI will fail if you don't add a social card.
The social images template lives at public/dev/social-card.html
. If you want to update it, navigate to the private dev routes /dev/social-card
and dev/audit-metadata
. The social-card route will let you see how the template looks in a tight feedback cycle, and audit-metadata can be used to check how the currently generated social cards look for every route.
During build, we pre-render every route so we can deliver a working site to viewers on first page load. The logic lives in scripts/lib/prerender.ts. Note that due to difficult-to-debug rehydration issues, we don't rehydrate the content on page load; rather, we wait for the app to fully load, and then replace the prerendered contents entirely.
We support three color themes: light, dark, and sunset. The themes are setup using tailwind v4 themes in themes.css, so we have theme-dependent colors like --color-background
, --color-foreground
, --color-muted
which update depending on the theme. When writing new UI code, avoid using hardcoded colors like --grey-300
(which, if it looks good on dark mode, will probably look bad on light mode, and vice versa). Instead, use the theme colors.
The website makes extensive use of MDX content for docs, blog posts, and policies. There is a unified content loading system in src/lib/content
which loads and processes the mdx, and makes it available to routes. All routes use TanStack data loaders so the content can be available at SSG prerender time.
All content is organized in the content/
directory at the project root, separated by content type:
content/docs/
- Documentation for Mirascope and Lilypad productscontent/blog/
- Blog postscontent/policy/
- Legal documents like privacy policy and terms of service
Development content for testing UI components is kept in src/components/dev/
since it's more closely tied to the components.
There are three content types, in order of increasing complexity: policy
, blog
, and doc
. Policy content is stuff like the privacy policy and we have hardcoded routes for each policy. Blog content includes the blog homepage and the many blog posts, but it's fairly straightforward. The doc
content splits across products (Mirascope and Lilypad), sections (like "API" and "Guides"), and groups and pages. The logic for handling these is somewhat convoluted with many special cases.
The content management system has a design doc at lib/content/DESIGN.md.
You can add new routes implicitly (by adding a new piece of mdx content that is covered by an existing route) or explicitly (by adding a new route to src/routes). In either case, it will get included in sitemap and the static build automatically, and you will need to generate a new social image for it via bun run generate-social --update
(or bun run generate-social --route /your/route
).
When adding a new explicitly, there are some considerations, please add an onError
handler to the route as follows:
onError: (error: Error) => environment.onError(error),
This is important, as it is the only way the static build will know if the component failed to render. This is because the Tanstack router automatically catches all errors and does not repropagate them, so otherwise the static build will seem to succeed but will prerender broken content.
Also, make sure you include a SEOHelmet component in the component served by your new route, so we'll have proper SEO metadata for that route.
We have a Cloudflare worker that does some request pre-processing for us, e.g. to get the country code so we can determine analytics policies. The worker is manually deployed, however we have the source checked in at cloudflare/worker.js. Also, we have a Cloudflare redirects file at public/_redirects, which is automatically processed by Cloudflare on build.
Python API docs (e.g. for mirascope) are generated by the scripts/apigen module. It depends on the target repo maintaining an api doc folder with markdown folders containing autodoc directives for documentation generation, and uses that folder's structure as the source of truth for the documentation structure.
Api docs are autogenerated (do not modify by hand), and they can be regenerated via bun run apigen
.
You can regenerate specific files with:
# Regenerate a specific file
bun run apigen --only llm/call.mdx
# Regenerate a specific file from a specific source
bun run apigen --only mirascope:llm/call.mdx
# Regenerate a file and update metadata
bun run apigen --only llm/call.mdx --with-meta
Sometimes, when running bun run start
, I see the following failure:
Port 3000 is available. Starting server...
failed to load config from /Users/dandelion/git/mweb-multi/mweb-2/vite.config.mjs
error when starting dev server:
Error: The service was stopped
In these occasions, rm -rf node_modules && bun install
fixes it.
Everything in this repository is licensed under the MIT License except for "Williams-Handwriting-Regular-v1.tff", which is a closed license font and not available for use without express permission.