Luna is a polyglot monorepo starter built around moonrepo for the task graph, proto for pinned runtimes, and the luna CLI (Rust, Starbase + Clap) for orchestration across all toolchain layers. Each stack brings its own runtime — Bun for JS/TS, Go for Hugo, Python for FastAPI — managed and pinned by Proto. It layers three application stacks: a SolidStart interactive app with SSR and streaming, a Hugo static site for Markdown and templates, and a FastAPI service with Pydantic and Pydantic AI. Shared libraries live under packages/*. Ports, environment files, and moon tasks are covered in the sections and READMEs below.
- 🌙 Moon (documentation) — task orchestration and project graph
- ⚙️ Proto — installs and pins all tools from
.prototools - 🦀 Rust — powers the
lunaCLI (packages/cli); pinned in.prototools
SolidStart on Vite and Nitro is the stack for SPA-style apps that need SSR, client-side fine-grained signals (SolidJS), routing (Solid Router), and streaming responses. Nitro gives you a server runtime alongside the browser bundle, so the same project can grow full-stack APIs and server logic without leaving the framework. Bun is pinned in .prototools as the JS/TS runtime and package manager for this stack.
- 🟢 Bun (documentation) — JS/TS runtime, package manager, and workspace resolver for
apps/appand shared packages - ⚛️ SolidStart (documentation) — full-stack app framework for
apps/app - 🧩 SolidJS (documentation) — reactive UI library
- 🔀 Solid Router — routing for Solid apps
- ⚡ Vite (guide) — dev server and build tooling
- 🔥 Nitro (guide) — server runtime used by SolidStart
- 🎨 Tailwind CSS v4 (documentation) — utility CSS used by
@luna/ds(consumed from the interactive app and the static site pipeline)
The apps/web project is a static-site workflow: Markdown and front matter in src/content/, Go HTML templates in src/layouts/, and the published site in dist/. @luna/ds styles are compiled by the Tailwind CSS v4 CLI into src/assets/css/bundle.css before each build (same design system as apps/app). Go is pinned in .prototools; the Hugo CLI version is pinned in apps/web/go.mod as a go tool (same idea as Python deps living under apps/api). See apps/web/README.md.
- 📰 Hugo (documentation) — static site generator; HTML, RSS, and sitemap from content + templates
- ✍️ Goldmark — CommonMark-compatible Markdown (Hugo’s default renderer)
- 🧩 Go HTML templates — partials, blocks, and
baseoflayouts undersrc/layouts/ - 🎨 Tailwind CSS v4 (documentation) — utility CSS for
@luna/ds(package);@tailwindcss/cliemitssrc/assets/css/bundle.css(same tokens asapps/app) - 🖍️ Chroma — syntax highlighting for fenced code blocks (
[markup.highlight]inhugo.toml)
The apps/api stack centers on FastAPI, Pydantic, and Pydantic AI for a pure backend HTTP API: validation, settings, and agent-style features stay on the server. The same patterns extend to larger deployments (multiple services, workers, or runtimes) when you outgrow a single process; this repo keeps one API project as the starting point.
- 🐍 Python — runtime (version pinned in
.prototools) - 📦 uv — environments and lockfiles
- 🚀 FastAPI — API framework
- 🤖 Pydantic AI — AI agent patterns on the backend
- ✅ Pydantic — schemas and models
- ⚙️ pydantic-settings — environment-driven settings
- 🌐 Uvicorn — ASGI server
- 🧹 OXC (
oxlint+oxfmt) (documentation) — linting and formatting for JS/TS at the repo root - 🟦 TypeScript (documentation) — static typing and project references across workspaces
Run commands from the repository root unless an app README says otherwise.
Install Proto and Moon on your PATH before setup (Moon is only needed until luna is installed; Proto pins moon, rust, bun, python, and go via .prototools).
After moon run cli:install, add ~/.cargo/bin to your PATH so the luna command is found (or use the full path in moon run luna:install below).
One command from the repo root (fresh clone or after luna clean):
moon run luna:installThat runs proto install → cli:build → cli:install → luna install (toolchains, CLI, bun workspaces, web, api). Then:
luna devEquivalent steps (if you prefer to run them separately):
proto install
moon run cli:build
moon run cli:install
luna installWithout luna on PATH yet — stop after cli:install, then:
./target/debug/luna install # or ~/.cargo/bin/luna installSubsequent refreshes: luna install. New pins in .prototools are picked up by proto install (or luna update, which refreshes pins then re-runs install). .moon/toolchains.yml disables javascript.installDependencies and sets bun.installArgs: ["--ignore-scripts"].
Full reset: luna clean, then moon run luna:install again. Each project’s inherited :clean task clears its own outputs; root luna:clean clears repo-root artifacts (node_modules, .venv, target, …); .moon/cache is removed last. Lockfiles are kept (bun.lock, uv.lock, Cargo.lock, go.work / go.sum).
For a full compile of every application project first, run luna build.
Local dev ports (copy .env.example → .env.local to customize): FastAPI / Uvicorn 8000 (common tutorial default — avoids stealing 3000 from the SPA), SolidStart 3000, Hugo static site 3001. Details and CORS URLs are in each app README.
apps/api/— FastAPI + Pydantic AI · READMEapps/app/— SolidStart (SSR, Vite, Nitro) · READMEapps/web/— Hugo + Tailwind v4 +@luna/ds· READMEpackages/cli/—lunaCLI (Rust + Starbase; orchestrates Moon/Proto/Bun commands;outdated/updateacross all toolchains)packages/ds/— design system / Tailwind · README- Entrypoints:
packages/ds/src/tailwind.css(main import),packages/ds/src/components.css,packages/ds/src/layouts.css,packages/ds/src/primitives.css - Modules:
packages/ds/src/{components,layouts,primitives}/*.css(authored as modular CSS) - Patterns: scoped root + nested layers (
@scope+@layer base|variants|patterns); see DS README
- Entrypoints:
packages/ui/— shared Solid UI · READMEpackages/py-demo/— demo Python uv workspace member (not for production)packages/go-demo/— demo Go workspace library (not for production);apps/weblinks it viaworkspace/link.go+replaceingo.mod(same idea as uvworkspace = true)
When updating packages/ds, follow the scoped root + nested layers CSS module pattern (@scope + @layer base|variants|patterns). The DS README is the source of truth: DS CSS patterns.
Moon wires build and dev tasks per project; api:dev depends on api:build (uv sync at the workspace root). luna install runs root uv sync (one shared .venv + uv.lock) and go work sync before luna dev. For step-by-step task graphs (luna build, Uvicorn, SolidStart), follow each workspace README above.
All day-to-day commands go through the luna CLI (packages/cli). It orchestrates Moon, Proto, and Bun directly — there are no root package.json scripts to remember.
luna install # bootstrap workspace
luna clean # :clean per project → moon clean --all → root luna:clean → .moon/cache last
luna dev # moon run :dev --query "projectLayer=application"
luna build # moon run :build --query "projectLayer=application"
luna start # moon run :start --query "projectLayer=application"
luna test # moon run :test --query "projectLayer=application"All build/dev/start/test commands accept an optional project name (luna build app) and --affected flag (luna build --affected).
luna orchestrates quality across all stacks in one command — TS (oxlint/oxfmt/tsc), Python (ruff via moon), Rust (cargo clippy/fmt), and Go (hugo config via moon):
luna lint # TS: oxlint, Python: ruff check, Rust: clippy
luna format # TS: oxfmt, Python: ruff format, Rust: cargo fmt
luna typecheck # TS: tsc --build, Go: hugo config
luna check # lint + format:check + typecheck (all stacks)
luna lint --fix # apply fixes (oxlint --fix, ruff --fix, clippy --fix)
luna format --check # check only (oxfmt --list-different, ruff --check, fmt --check)
luna fix # lint:fix + format (all stacks)Pass multiple project:task targets to run them in one invocation:
moon run app:dev api:dev # interactive app + API only (no web)
moon run app:build api:build web:buildUse --query to filter the graph instead of listing every target (same query language as moon query projects):
moon run :dev --query 'project=[app,api]'
moon run :typecheck --query "projectLayer=library" # shared packages (per-project inherited tasks)
moon query projects --help # filters: --id, --language, --layer, etc.Examples for shared packages (see each package README for inherited tasks):
moon run ds:typecheck
moon run ui:typecheck-
Tool/version pins:
.prototools -
Workspace manifest + dev dependencies:
package.json— Bun workspaces and dev tool versions only; all orchestration goes throughluna -
Python workspace (uv):
pyproject.toml— virtual root, shareduv.lock+.venv; membersapps/api,packages/py-demo; shared ruff/pytest dev tooling in root[dependency-groups] -
Go workspace:
go.work— membersapps/web,packages/go-demo -
Rust workspace:
Cargo.toml— memberpackages/cli -
Moon workspace graph + VCS:
.moon/workspace.yml -
Moon toolchains:
.moon/toolchains.yml—javascript.installDependencies: false,bun.installArgs: ["--ignore-scripts"]; bootstrap withluna install. After changing JS deps, runbun installorluna install. -
Shared TS app tasks:
.moon/tasks/ts-app.yml(language: typescript,layer: application,stack: frontend) -
Shared TS lib tasks:
.moon/tasks/ts-lib.yml(language: typescript,layer: library) -
Shared Python API tasks:
.moon/tasks/py-api.yml(language: python,stack: backend) -
Shared Python lib tasks:
.moon/tasks/py-lib.yml(language: python,layer: library) -
Shared Go web tasks:
.moon/tasks/go-web.yml(language: go,stack: frontend) —go tool hugofromapps/web/go.mod -
Shared Go lib tasks:
.moon/tasks/go-lib.yml(language: go,layer: library) -
Root workspace tasks:
moon.yml—luna:install(first-time bootstrap),luna:clean(repo-root outputs only;.moon/cachedropped last byluna clean) -
Shared Rust bin tasks:
.moon/tasks/rs-bin.yml(language: rust) — build/install/test/lint/format-check/clean viacargo -
Root moon config:
moon.yml -
TypeScript project graph:
tsconfig.json -
Shared TypeScript options:
tsconfig.options.json -
OXC formatter config:
.oxfmtrc.json -
OXC linter config:
.oxlintrc.json
Repo-wide outdated checks and upgrades go through the luna CLI so every toolchain stays in sync:
The luna CLI (packages/cli, built with Rust + Starbase) reports outdated tiers in order: proto → Rust / Cargo (cargo outdated) → Bun → Python / uv (root lockfile dry-run) → Go per go.mod. Hugo-style modules (tool in go.mod, local code only under workspace/) use go list -m -u on tool lines; other modules use direct go list -m -u (not the full workspace graph). Set LUNA_GO_FULL_GRAPH=1 to scan or update with go list -m -u all / go get -u all. luna outdated prints a summary and exits 0 (findings are informational). luna update follows the same order, then re-runs install (uv sync, go work sync). After luna update, review diffs and run luna check before committing.
luna outdated # report + summary (exits 0)
luna update # bump pins and dependencies repo-wide; then review and run luna check
luna update --major # also apply major-version bumps where supportedPer stack (manual add / remove) — use these when you are changing one project, not refreshing everything:
- Toolchain (proto) — edit
.prototools, thenluna installorproto installindividually. Removing a tool line drops it from proto’s install set for this repo. - Hugo (
apps/web) —luna updatebumps thetoolline withgo get -u=patch(orgo get -tool …@latestwithluna update --major). To pin a specific release manually:cd apps/webthengo get -tool github.com/gohugoio/hugo@vX.Y.Z(updatesapps/web/go.mod/go.sum). SetLUNA_GO_FULL_GRAPH=1to restore slow full-graphgo get -u allon tool-only modules. - Bun / workspaces — from the repo root, add to a workspace with
bun add <pkg> --cwd apps/app(or--cwd packages/ui, etc.); usebun add -d <pkg> --cwd <path>for devDependencies. Remove withbun remove <pkg> --cwd <path>. Root-only deps:bun add <pkg>at the root. - Python (uv workspace) — from the repo root:
uv add <package> --package api/uv remove <package> --package api(updates memberpyproject.tomland rootuv.lock); sync withuv syncorluna install. Add a new member in rootpyproject.toml[tool.uv.workspace]and use[tool.uv.sources] name = { workspace = true }for inter-member deps.
Install the CLI (~/.cargo/bin must be on your PATH):
moon run cli:build
moon run cli:install
luna --helpTo run without installing, build and invoke the debug binary ( target/ is gitignored):
moon run cli:build --force
./target/debug/luna --helpAnother process is still bound to the port (often after stopping a dev server).
lsof -i :8000 # API (Uvicorn) default; :3000 app; :3001 webNote the PID from lsof, then:
kill -9 <PID>If you know the command line, you can narrow cleanup:
ps aux | grep -E "(uvicorn|vite)" | grep -v grep
pkill -f "uvicorn src.main:app" # API (adjust if your entrypoint differs)