fuzzyworld-tools / files / docs / code-site.md
code-site.md
bb7e1f57 2026-11-06 Pavel Safronov | 1 | # The code site (code.fuzzyworld.net) |
| 2 | ||
| 3 | Static pages for every public repo, generated by `server/gen.py` on each push (the `post-receive` hook starts | |
| 4 | `fw publish <name>` in the background, so a push returns at once and pages update 1-5 seconds later). Every repo uses | |
| 5 | the shared hook through `core.hooksPath=~/fw/tools/server/hooks`. | |
| 6 | ||
| 7 | Who sees what is set per repo; see [Visibility](../README.md#visibility). | |
| 8 | ||
| 9 | ## Page URLs | |
| 10 | ||
| 11 | ### Repo pages | |
| 12 | ||
| 13 | | URL | Page | | |
| 14 | |---|---| | |
| 15 | | `/` | index of public repos: a table, newest code commit first, with description and an app link | | |
| 16 | | `/<name>/` | summary: description, clone command, "Open in VS Code" links, license, CI status, screenshots, recent commits, README | | |
| 17 | | `/<name>/tree/<dir>/` | directory listing (default branch) | | |
| 18 | | `/<name>/blob/<path>.html` | file view with line numbers and syntax highlighting (Pygments; files ≤ 512 KB); `.md` files rendered | | |
| 19 | | `/<name>/history/<path>.html` | commits that changed the file (up to 200; renames not followed) | | |
| 20 | | `/<name>/blame/<path>.html` | the commit that last changed each line (text files ≤ 256 KB) | | |
| 21 | | `/<name>/raw/<path>` | raw copies of images only (png, jpg, gif, webp, ico, avif, bmp, svg; ≤ 2 MB) | | |
| 22 | | `/<name>/log/` | the branch's commits (up to 2000) | | |
| 23 | | `/<name>/commit/<sha>.html` | one commit with its diff (truncated at 300 KB); a page for every commit on every branch, up to 2000 per repo | | |
| 24 | | `/<name>/refs/` | branches and tags | | |
| 25 | | `/<name>/branch/<branch>/...` | the same tree/blob/history/blame/log pages for another branch; `/` in a branch name is written `~` | | |
| 26 | ||
| 27 | ### Pages for features | |
| 28 | ||
| 29 | | URL | Page | | |
| 30 | |---|---| | |
| 31 | | `/<name>/ci/`, `/<name>/ci/<sha>.html` | CI pipelines (newest 100) and one pipeline with its job logs ([ci.md](ci.md)) | | |
| 32 | | `/<name>/ci/badge.svg` | status of the latest pipeline on the default branch | | |
| 33 | | `/ci/` | CI dashboard: running pipelines, the queue, the last 50 results, for public repos | | |
| 34 | | `/<name>/issues/`, `/<name>/issues/<n>/` | bug-report issues, when the repo's mode and the issue's state allow it ([issues.md](issues.md)) | | |
| 35 | | `/<name>/usage/` | Claude Code usage per commit and per session, only for repos with usage trailers ([usage.md](usage.md)) | | |
| 36 | | `/usage/` | the same, summed over all public repos ([usage.md](usage.md)) | | |
| 37 | | `/<name>/files.json`, `/<name>/objects/<sha>` | for VS Code in the browser: every file's blob SHA and size, and each file's contents (≤ 1 MB) | | |
| 38 | ||
| 39 | ### Site pages | |
| 40 | ||
| 41 | `/projects/`, `/why-i-left-gitlab/`, `/my-ai-use/` and `/contribute/` are files in `server/content/`, rendered by | |
| 42 | `fw content` into the common page layout. | |
| 43 | ||
| 44 | - A file is Markdown, or an HTML fragment with a leading `<!-- title: … -->`. | |
| 45 | - An image in that folder that a page mentions (``) is copied next to the page. | |
| 46 | - A file starting with `_` (the `/how/` draft) is not built. | |
| 47 | - `/why/` and `/principles/` redirect to `/why-i-left-gitlab/`; the old `fuzzyworld.net/projects/` redirects to `/projects/`. | |
| 48 | - `fw content` also writes `404.html`. | |
| 49 | ||
| 50 | `/ci/`, `/usage/` and the other site pages cannot be repo names (repos with those names are skipped). | |
| 51 | ||
| 52 | ## Branches | |
| 53 | ||
| 54 | The default branch, and every branch **not yet merged** into it, get browse pages. A merged branch adds nothing new | |
| 55 | to read and would duplicate every page, so the branches page lists it with a link to its last commit. Every branch | |
| 56 | and tag can be cloned. Author email addresses are not shown. | |
| 57 | ||
| 58 | ## License detection | |
| 59 | ||
| 60 | The summary page names the repo's license, read from a root `LICENSE`, `LICENCE` or `COPYING` file (MIT, Apache-2.0, | |
| 61 | GPL, LGPL, AGPL, MPL-2.0, BSD, ISC, Unlicense, CC0), else from `package.json`. | |
| 62 | ||
| 63 | ## Preview locally | |
| 64 | ||
| 65 | `npm run dev` builds this repo's pages into a temp directory and serves them at <http://localhost:8000/>. | |
| 66 | ||
| 67 | - Pass other working copies after `--`: `npm run dev -- ~/code/explodorama`. | |
| 68 | - Set `PORT` to change the port. | |
| 69 | - It uses each repo's committed state. `server/site/*.css` edits show on reload; a change to `gen.py` needs a restart. | |
| 70 | ||
| 71 | ## Security | |
| 72 | ||
| 73 | The site never executes anything from a repo. | |
| 74 | ||
| 75 | | Rule | How | | |
| 76 | |---|---| | |
| 77 | | Pages are pre-generated | all repo content is HTML-escaped | | |
| 78 | | Raw files are images only | written only for image extensions; `.htaccess` also denies `.php`, `.shtml`, `.cgi`, `.pl`, `.py` and `.sh` and disables SSI/CGI (DreamHost runs `.php` files and SSI otherwise; tested 2026-10-26) | | |
| 79 | | No scripts | `Content-Security-Policy: script-src 'none'` on every response, which also covers SVG images | | |
| 80 | | Clone copies hide internals | inside public clone copies, `config`, `description`, `hooks/` and `logs/` return 404 | | |
| 81 | | File contents never render | `objects/<sha>` is always sent as `application/octet-stream` with `Content-Disposition: attachment`, so a repo's `.html` or `.svg` can never render as a page. `files.json` and `objects/` allow cross-origin reads, because VS Code runs on apps.fuzzyworld.net | | |
| 82 | | CI logs are escaped | CI pages exist only for public repos | | |
| 83 | ||
| 84 | apps.fuzzyworld.net gets the same server-side no-execution rules (no PHP, SSI or CGI). Apps themselves run | |
| 85 | JavaScript in the browser, so the apps site sends no script-blocking policy. HTML, service workers and manifests are | |
| 86 | sent with `no-cache` (a deploy is seen at once); `/<app>/assets/` (hashed by vite) is cached for a year. |