Skip to content

Guides

Project structure

Know where routes, shared UI, and content belong.

View as Markdown

A small monorepo

api/
  models/                   Authored JSON Schema wire models
  generated/                Generated self/cloud OpenAPI snapshots
server/
  core/                     Shared Effect services, PostgreSQL and Better Auth
  cloud/                    Cloud-only backend extensions
web/
  web-deploy-cloud/         Node/Start: shared app + cloud-only features
    src/document.tsx        Cloud HTML document and theme
    src/public-shell.tsx    Public navigation, search, account and footer composition
    src/routes/_site.tsx    Public shell route
    src/routeTree.gen.ts     Cloud-generated route tree
    src/server.ts           Backend-first Start server entry
    src/routeTree.gen.ts     Self-generated route tree
    Dockerfile              Multi-stage app-only image
  web-router/
    src/vite.ts             Shared virtual-route/Vite composition
    src/backend.server.ts   Shared backend lifecycle adapter
  web-app/
    src/routes/             Application routes (starts at /app)
  web-community/
    src/experiments.ts      Static gallery metadata; no model imports
    src/demo/               Shared checked, cancellable browser runtime
    src/routes/             Cloud-only gallery, experiments and disabled login
  web-og/
    src/routes/             Cloud-only OG image route
  web-status/
    src/routes/             Cloud-only status page scaffold
  web-shell/
    src/site-shell.tsx      Shared runtime shell for cloud public pages and /app
  web-landing/
    src/routes/             Cloud-only homepage route and metadata
    src/home/               Session-aware SSR homepage
  web-content/
    src/routes/             Docs/blog/changelog metadata and Markdown endpoints
    src/docs/               Documentation screens
    src/blog/               Blog screens
    src/changelog/          Changelog screens and styles
    src/llms.ts             LLM indexes over published content
    src/markdown.ts         Shared Markdown renderer
    src/content.ts          Typed content selectors
    content/docs/           Documentation in Markdown
    content/blog/           Blog posts in Markdown
    content/changelog/      Changelog updates in Markdown
    content-collections.ts  Content schemas and transforms
  api/                      Generated fetch client; public @tinyrobot/api entry
  ui/
    src/components/         Shared UI and public proxies
    src/generated/          Upstream-owned components
  analytics/                Standalone Cloudflare analytics Worker
  github/                   Standalone Cloudflare GitHub App Worker
sdk/py/                  Python SDK (PyPI: tinyrobot)
sdk/js/                  JavaScript/TypeScript SDK (npm: tinyrobot)
experiments/             Isolated tinygrad training/export projects and demo kit

Routes and layouts

Features own route files, loaders, not-found decisions and metadata. web/web-router uses virtual routes to compose physical feature directories. Each deployment owns its root route, router factory and generated src/routeTree.gen.ts.

web/web-content owns docs (including printer monitoring and use cases), blog, changelog, and their shared Markdown/LLM pipeline. web/web-landing owns the cloud-only homepage. Public pages nest under the cloud deployment's _site route, which supplies navigation, search, account controls, and footer to web/web-shell; /app and /printers use that same shell in compact mode in cloud. /llms.txt and /llms-full.txt use the published content pipeline. web/web-app contains the client-rendered application at /app and the private /printers monitor. web/web-community owns the trusted /community/ gallery and experiments; /demos/cartpole permanently redirects to /community/cartpole. web/web-og owns the /og PNG endpoint, and web/web-status owns the /status scaffold. Features use TanStack Router directly. Cloud mounts public and shared features; the app-only self-hosted web deployment is removed for now. Landing/public content/community/analytics/OG/status/invite and the cloud backend are excluded from the shared shell and self-hosting, not merely hidden in navigation.

Each deployment has a separate TypeScript program and router registration. Never import both generated route trees into one program. Feature-only checks use generated type-only route declarations. Run the owning deployment's generate command after route changes; pnpm routes:check checks both trees and declarations without rewriting sources or outputs, before full/affected checks can regenerate them.

Browser experiment library

Visit Community for CartPole, two-link reaching, action-chunk cube pushing, trajectory denoising, pendulum control, handwritten digits and visual target following, plus a curated Hugging Face Space. Local models run only after Start, using WebGPU or explicitly selected JavaScript CPU. The Space is external and can process inputs remotely.

The contributor experiment index links every method, dataset, release gate and reproducible training/export command. Robotics scenes are synthetic teaching tasks, not hardware-ready controllers; MNIST results do not guarantee arbitrary handwriting recognition. Training is isolated Python, never a dependency of web builds or a server inference service.

Splat routes support nested content paths, so web/web-content/content/docs/guides/example.md becomes /docs/guides/example, with its Markdown counterpart at /docs/guides/example.md.

Backend and generated contracts

The cloud Node deployment sends /health, /openapi.json, /api and /api/* to the backend before TanStack Start, including JSON 404s for unknown API paths. Core owns shared auth and Effect resource lifetimes; cloud composes extensions without leaking them into self. Better Auth's supported Promise/pg adapter and native Effect PostgreSQL queries share the database and generated schema, but use separate pools and transaction scopes.

Author wire models in api/models, then run pnpm api:generate in core → cloud → web client order. Import web clients only through @tinyrobot/api; never edit generated models, OpenAPI or client files. See the backend guide and API contract guide.

Python serves SDK and robotics work, not HTTP. The SDKs release independently through py-vX.Y.Z and js-vX.Y.Z tags; web checks need no uv and Python checks need no Node. Nx orchestrates local tasks only, with no remote cache. Website hosting migration and community login activation remain deferred; standalone Workers are not the website host.

Shared UI

Generic slot-based layout components and UI proxies belong in web/ui/src/components. Runtime shell behavior lives in web/web-shell; navigation and optional footer/search/account controls are composed by callers. Cloud owns its public composition without adding public routes or dependencies to self-hosting.

Use public imports such as @tinyrobot/ui/components/button. Generated shadcn components use Base UI and are wrapped by public proxies. Never edit upstream-owned files in web/ui/src/generated directly.

Framework conventions

This follows TanStack Start's routing conventions: file-based routes, nested layouts, typed links, route loaders, and route-level metadata.

TanStack Router's ESLint plugin runs inside oxlint through JavaScript plugins for route property ordering and route parameter names. TanStack Start's server/client rules are deferred because they require type-aware parser services that Oxlint's JavaScript plugin API does not provide. There is no separate ESLint command.