From ccea4e44503001b9c96b0e43f3608e71383441e4 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 23:17:25 -0700 Subject: [PATCH 1/2] Claim quest/m0/lean-agents-md Co-Authored-By: Claude Opus 5.5 From 4335435d8e81d94eff2b88f845b81ce0f6405226 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 23:19:25 -0700 Subject: [PATCH 2/2] Trim AGENTS.md to rules and conventions Drop the repository description (site table, commands, stack, architecture, URL scheme, deployment, tips): the README and code comments already cover it. The Bun pin-sync guidance moves into the flake assertion message, and the watch-link token rule becomes a comment beside the code that builds the link. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 133 ++----------------------------------- flake.nix | 2 +- quest/m0/README.md | 4 +- quest/m0/lean-agents-md.md | 19 ------ sites/pub/src/main.ts | 2 + src/lib/try.ts | 2 + 6 files changed, 11 insertions(+), 151 deletions(-) delete mode 100644 quest/m0/lean-agents-md.md diff --git a/AGENTS.md b/AGENTS.md index be9e6d0..0ee4bd1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,37 +1,6 @@ -# AGENTS.md +Read `README.md` for the three sites (moq.dev, moq.pub, moq.watch), setup, and the broadcast URL scheme. -## Project Overview - -moq.dev is a web blog and demo for Media over QUIC (MoQ) protocol. It's built with Astro, Solid.js, and uses WebTransport to connect to MoQ relay servers for live streaming. - -The repo holds three sites, each its own Cloudflare Worker but built and deployed together: - -| Site | Source | What it is | -|-------------|-------------|-------------------------------------------------------| -| `moq.dev` | `src/` | The Astro blog and demos | -| `moq.pub` | `sites/pub` | A bare `` publisher, no framework | -| `moq.watch` | `sites/watch` | A bare `` player, no framework | - -## Essential Commands - -```bash -# Development -just dev # Start the moq.dev dev server with auto-open -just dev-pub # moq.pub on :5174 -just dev-watch # moq.watch on :5173 - -# Build & Deploy -just build # Production build of all three sites -just deploy # Deploy all three to Cloudflare (staging by default) -just deploy live # Deploy to production -just prod # Build and preview production locally - -# Code Quality -just check # Run Biome linting and TypeScript checking -just fix # Auto-fix code formatting/lint issues -``` - -## Required +# Required - Dig into the root cause and fix it at the source. Never work around a fixable bug with a retry, sleep, or timeout. - Fail loud and early. Error on unsupported or malformed input rather than warn and continue. @@ -49,7 +18,7 @@ just fix # Auto-fix code formatting/lint issues - Add the AI marker `(Written by )` to any posts on GitHub, excluding commit messages that contain `Co-Authored-By:` trailers. - Any AI comments may be challenged, and not confused with human maintainers. -## Guidelines +# Guidelines - Comments should explain the non-obvious why, and never the history. - Inline simple helpers. @@ -63,102 +32,10 @@ just fix # Auto-fix code formatting/lint issues - Try to do stuff asynchronously. ex. ask about follow-ups while checks run. - If the core problem is addressed, ship it instead of spinning your wheels on meaningless revisions. -## Development +# Development PRs target `main`. Before starting, `git fetch origin` and set the upstream to the base branch. `git stash` is one stack shared by every worktree; set work aside with a commit instead. Use the Nix dev shell (direnv, or `nix develop --command just ...`) so tooling matches CI. -Run `just fix` before committing. `just check` alone is not verification: look at the change in the dev server. +Run `just fix` before committing. `just check` alone is not verification: look at the change in the dev server (`just dev`, `just dev-pub`, or `just dev-watch`). Quests: when work mentions a quest, run `quest guide` and follow it. The `quest` binary comes from the kixelated/quest flake input and serves the quest skills; change them upstream and bump the input. - -## Architecture Overview - -### Technology Stack -- **Framework**: Astro (static output) -- **UI Components**: Solid.js for interactive elements -- **Styling**: Tailwind CSS -- **Build**: Vite -- **Code Quality**: Biome for linting/formatting -- **Package Manager**: bun -- **Task Runner**: just -- **Toolchain**: pinned in `flake.nix`; `nix develop` (or direnv, via `.envrc`) provides bun, node, and just - -The Bun version in nixpkgs must match `packageManager` in `package.json`. -CI reads its version from `package.json` and evaluates the flake assertion to -catch drift. When a weekly Dependabot Nix update changes Bun, update -`package.json` in the same PR. - -### Key Components - -**MoQ Client Implementation** (`@moq/publish` + `@moq/watch` packages): - - Custom web components: ``, `` - - UI wrapper components: ``, `` - -### Important Patterns - -- **No REST APIs**: Uses WebTransport directly for streaming -- **Stateless**: No database or user management -- **Error Handling**: Component-level with `src/components/fail.tsx` -- **Authentication**: Basic JWT support via query parameters for demo broadcasts -- **Content Management**: MDX files in `src/pages/blog/` for documentation - -### The moq.pub / moq.watch URL scheme - -A broadcast is identified by its path: `//`, e.g. -`moq.pub/try/h2z15dgmdh.hang`. The project is the relay tenant and the -name is everything after it, so names may contain slashes. The same path on -either site refers to the same broadcast: publish at `moq.pub/try/x.hang` and -watch it back at `moq.watch/try/x.hang`. - -Anything that *isn't* part of the broadcast's identity stays in the query -string: `?relay=`, `?cloudflare=`, `?jwt=`, and -(moq.pub only) `?source=camera`. `?cloudflare=draft-16` is shorthand for -`https://draft-16.cloudflare.mediaoverquic.com`; the project path segment still -carries Cloudflare's relay token. `cloudflare` and `relay` are mutually -exclusive. - -A bare `moq.pub/` mints a private broadcast in the `try` project from -`POST ${PUBLIC_API_URL}/try/token` and keeps the publish token in its own URL. -**A watch link never carries `?jwt=`**: moq tokens are prefix-scoped with -separate publish (`put`) and subscribe (`get`) grants, so a shared publish token -lets anyone publish. moq.pub links to moq.watch only for `try` on the default -relay, and moq.watch mints its own subscribe token from `/try/watch` for a -tokenless `try` path. Other projects get no link; swap the hostname. - -`sites/lib` holds the scheme itself, shared by both sites and by both the Worker -and the Vite dev server so they can't drift: - -- `broadcast.ts`: parse and build `//`, and the relay URL -- `route.ts`: old `?project=&name=` links redirect into the path -- `try.ts`: mint `try` credentials from the API -- `worker.ts`: the Worker both sites export -- `dev.ts`: a Vite plugin giving `just dev-pub` / `just dev-watch` the same - routing (`just dev` is the Astro site and doesn't use it) - -Two things are easy to break here: - -- `assets.run_worker_first: ["/"]` in each `wrangler.jsonc` is load-bearing. `/` - matches `index.html`, so without it Cloudflare's asset server answers first and - the Worker never runs and old `?project=&name=` links don't redirect. -- The Worker can't decide "asset vs. page" by looking for a dot, because names - end in `.hang`. It asks the asset store and falls back to the page on a 404. - -### Deployment - -- Cloudflare Workers via Wrangler, one per site -- `just deploy` for staging, `just deploy live` for production -- Deploys are manual; nothing ships on merge to `main` - -`just deploy ` builds all three sites in that mode and uploads each Worker. -The player sites read the repo-root `.env.` files that the Astro site uses, -so `PUBLIC_RELAY_URL` is the single place the relay is configured. Staging is -`new.moq.dev`, `new.moq.pub`, and `new.moq.watch`. - -The player sites deploy before moq.dev. - -## Development Tips - -- Broadcasts are ephemeral - no persistence layer -- The `@moq/publish` and `@moq/watch` packages handle all MoQ protocol implementation -- For new blog posts, add MDX files to `src/pages/blog/` -- Component changes in `src/components/` automatically reload with HMR diff --git a/flake.nix b/flake.nix index 346d4f4..661334d 100644 --- a/flake.nix +++ b/flake.nix @@ -40,7 +40,7 @@ devShells.default = assert pkgs.lib.assertMsg ((builtins.fromJSON (builtins.readFile ./package.json)).packageManager == "bun@${pkgs.bun.version}") - "Update package.json to match Nix Bun ${pkgs.bun.version}"; + "Bun pins disagree: packageManager in package.json must be bun@${pkgs.bun.version}, the Bun in the pinned nixpkgs. Update them together."; pkgs.mkShell ( { packages = with pkgs; [ diff --git a/quest/m0/README.md b/quest/m0/README.md index f55a15d..2bc91e4 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -5,12 +5,10 @@ The sites host the `@moq` player worklets and workers themselves, so the hosted path gets real traffic. -The agent context is lean and the checks cover what they claim, passing on a -developer's machine. +The checks cover what they claim, passing on a developer's machine. ## Required -- [Lean AGENTS.md](/quest/m0/lean-agents-md.md) - agent context keeps only rules and conventions, no repo description - [Biome passes locally](/quest/m0/biome-local.md) - `just check` passes with Claude Code's local files present - [Type-check .astro files](/quest/m0/astro-typecheck.md) - `just check` covers `.astro` via the TypeScript 7.1 content mapper - [Dogfood hosted worklets](/quest/m0/dogfood-assets.md) - the sites serve the @moq worklets and workers themselves diff --git a/quest/m0/lean-agents-md.md b/quest/m0/lean-agents-md.md deleted file mode 100644 index 20d8695..0000000 --- a/quest/m0/lean-agents-md.md +++ /dev/null @@ -1,19 +0,0 @@ -# [S] Lean AGENTS.md - -## Goal - -AGENTS.md holds only the rules and conventions that steer agents, in the shape -of [moq-dev/moq's root AGENTS.md](https://github.com/moq-dev/moq/blob/main/AGENTS.md). -The repository description leaves it: the site table, command list, tech stack -and version pins, architecture, URL scheme, deployment, and tips. Stale facts -like the Bun version stop drifting because they are no longer written down. - -## Plan - -- Delete rather than relocate. The README already explains the three sites and - the URL scheme, and the two easy-to-break pitfalls are comments next to the - code (`sites/*/wrangler.jsonc`, `sites/lib/worker.ts`). If something - load-bearing turns out to be missing, add it as a comment beside that code. -- The Bun pin-sync rule goes too. Make the flake's Bun assertion failure name - both pins (nixpkgs and `packageManager` in `package.json`), so the guidance appears exactly when CI catches the drift. -- Read `PROMPTING.md` first. `CLAUDE.md` is a symlink to `AGENTS.md`. diff --git a/sites/pub/src/main.ts b/sites/pub/src/main.ts index c5bdc21..3b4cb06 100644 --- a/sites/pub/src/main.ts +++ b/sites/pub/src/main.ts @@ -54,6 +54,8 @@ function mount(broadcast: Broadcast.Broadcast, params: URLSearchParams) { const ui = document.createElement("moq-publish-ui"); ui.appendChild(publish); + // Only here does moq.watch mint its own subscribe token. Share the bare path: + // this page's ?jwt= is a publish token, and would let anyone publish. if (broadcast.project === "try" && !params.has("relay") && !params.has("cloudflare")) { const share = new URL(import.meta.env.PUBLIC_WATCH_URL); share.pathname = Broadcast.path(broadcast); diff --git a/src/lib/try.ts b/src/lib/try.ts index 21c823b..e07be58 100644 --- a/src/lib/try.ts +++ b/src/lib/try.ts @@ -10,6 +10,8 @@ export async function publish() { import.meta.env.PUBLIC_RELAY_URL, ); if (!url) throw new Error("Invalid relay configuration."); + // The bare path: the watch page mints its own subscribe token, and the + // publish token would let anyone publish. const share = new URL(import.meta.env.PUBLIC_WATCH_URL); share.pathname = Broadcast.path(broadcast); return { broadcast, url, share: share.toString() };