fuzzyworld-tools / commit
Site pages in Markdown: /why/ is server/content/why.md
PLAN.md | 11 ++++------- README.md | 2 +- server/content/why.md | 29 +++++++++++++++++++++++++++++ server/fw | 2 ++ server/gen.py | 22 ++++++++++++++++++++++ server/install.sh | 2 +- server/site/why/index.html | 44 -------------------------------------------- 7 files changed, 59 insertions(+), 53 deletions(-) diff --git a/PLAN.md b/PLAN.md index 9d6ad75..4aa51f8 100644 --- a/PLAN.md +++ b/PLAN.md @@ -91,6 +91,8 @@ The order goes from cheap to expensive, and each step reuses what the one before - CI `cache:` support (a per-repo volume on TrueNAS), and `services:` - Branch pages: link to the default branch's page when a file is identical, instead of a copy - Found in review (2026-10-27): discussed, not done + - Site pages in Markdown: `/why/` done (`server/content/why.md`, `gen.py content`). Still HTML: `/principles/`, + `/contribute/`, `/how/` draft, `404.html` - `/how/` goes live: finish the draft, add it to `server/install.sh` (`/why/` already says it is coming) - CI runner tags (`docker`, `chrome`, `android`) and the laptop as a second runner (`fw-runner.py --once`): designed, not built; there is one runner, and it takes every job @@ -115,13 +117,8 @@ Wording approved 2026-10-26: > Things made with AI should be shared freely with the world. The code and apps here were made with > AI, so they are MIT-licensed: use them, change them, share them. > -> My conversations with the AI are different. My words and my way of working are mine. I publish a -> conversation only when I choose to, I can take that permission back, and nobody may copy my words or -> my style of work without my express permission. - -**Style** (keep this note with the wording). Copyright protects my words; it generally doesn't protect a -style or a way of working. "Nobody may copy my style" is therefore a statement of my terms and wishes, -not something a license can enforce. The wording is written to be honest about that. +> My conversations with the AI are different. My words and my way of working are mine to publish or not. +> I will publish a conversation only when I choose to. ## CI diff --git a/README.md b/README.md index a99ca68..837b14e 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ Every repo uses the shared hook via `core.hooksPath=~/fw/tools/server/hooks`. `p | `/<name>/ci/badge.svg` | status of the latest pipeline on the default branch | | `/ci/` | CI dashboard: running pipelines (each job's state and time), the queue, the last 50 results, for public repos | | `/<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) | -| `/why/`, `/principles/`, `/contribute/` | about the site | +| `/why/`, `/principles/`, `/contribute/` | about the site. `/why/` is written in Markdown (`server/content/why.md`, rendered by `fw content`); the other two are still hand-written HTML in `server/site/` | **Branches:** the default branch, and every branch **not yet merged** into it, get browse pages. A merged branch adds nothing new to read and would duplicate every page, so the branches page lists it with a link to its last diff --git a/server/content/why.md b/server/content/why.md new file mode 100644 index 0000000..1c4a584 --- /dev/null +++ b/server/content/why.md @@ -0,0 +1,29 @@ +title: Why this site exists + +# Why I left GitLab + +On Monday, October 26, 2026, I came back to work after a week's vacation to Friday Harbor. While on vacation I did what I like to do for fun and made a turn-based rogue-like Bomberman clone. +So back at work, I was thinking of sharing it with some coworkers, +but very quickly GitLab showed me a "Rate limit exceeded" error. And I rapidly learned that GitLab enacted +some rate-limiting policies recently that blocked repo access at work, and, very quickly, even +access to GitLab itself! + +So yeah, I couldn't look at my personal code at work, and that pissed me off, and now all of my code and +projects are hosted on Dreamhost, where I already keep a blog and a lightweight webpage. + +- code: <https://code.fuzzyworld.net/> +- apps: <https://apps.fuzzyworld.net/> + +No rate limiting, no sign-in, no "modern" limits. This is a static website! What more do I really need? + +I'm currently trying to formalize the process of the move from GitLab to Dreamhost, and eventually my +learnings are going to be at /how/ on this website. + +## Principles + +Things made with AI should be shared freely with the world. The code and apps here were made with +AI, so they are MIT-licensed: use them, change them, share them. + +My conversations with the AI are different. My words and my way of working are mine. I publish a conversation only when I choose to. + +More on the [principles](/principles/) page. diff --git a/server/fw b/server/fw index a48aef7..248b773 100755 --- a/server/fw +++ b/server/fw @@ -11,6 +11,7 @@ # fw publish-all publish every public repo, then the index # fw install-hooks point every repo at the shared hooks # fw apps-index rebuild the apps.fuzzyworld.net index +# fw content render the Markdown site pages (server/content/*.md, e.g. /why/) # fw app-deployed <app> <repo> after `fw deploy`: apps index, plus the repo's code page # fw ci <name> [branch] queue a CI run of a branch's latest commit (default: the default branch) # fw ci-queue <name> <ref> <sha> queue a CI run (the push hook runs this) @@ -224,6 +225,7 @@ cmd_ci_watch() { mkdir -p "$STATE" "$LOGS" case "${1:-}" in apps-index) "${GEN[@]}" apps ;; + content) "${GEN[@]}" content ;; app-deployed) cmd_app_deployed "${2:-}" "${3:-}" ;; list) cmd_list ;; new) shift; cmd_new "$@" ;; diff --git a/server/gen.py b/server/gen.py index dfba4c8..096ad01 100755 --- a/server/gen.py +++ b/server/gen.py @@ -4,6 +4,7 @@ gen.py repo <name> build or update the pages of one public repo gen.py index rebuild the site index (public repos only) gen.py apps rebuild the apps.fuzzyworld.net index from deployed apps + gen.py content render server/content/<name>.md to code.fuzzyworld.net/<name>/ (site pages written in Markdown) gen.py ci <name> rebuild one public repo's CI pages, then the CI dashboard gen.py ci-dashboard rebuild code.fuzzyworld.net/ci/ (queue, running, recent; public repos only) gen.py ci-status the same, as text for the terminal, private repos included (fw ci-watch) @@ -508,6 +509,25 @@ def render_markdown(text, ctx): return _ATTR.sub(fix, out) +CONTENT = os.environ.get("FW_CONTENT", os.path.join(os.path.dirname(os.path.abspath(__file__)), "content")) + + +def build_content(): + """Site pages written in Markdown: content/<name>.md becomes <site>/<name>/index.html. + A `title: ...` line at the top of the file is the page title (Python-Markdown's meta extension).""" + if not markdown: + raise SystemExit("gen.py content needs Python-Markdown in " + PYLIB) + for name in sorted(os.listdir(CONTENT)): + stem, ext = os.path.splitext(name) + if ext != ".md": + continue + with open(os.path.join(CONTENT, name), encoding="utf-8") as f: + md = markdown.Markdown(extensions=["meta", "tables", "fenced_code", "sane_lists"], output_format="html") + body = md.convert(f.read()) + title = " ".join(md.Meta.get("title", [stem])) + write(os.path.join(SITE, stem, "index.html"), page(title, body)) + + # ---------------------------------------------------------------- highlighting # Pygments token types folded into a few CSS classes (colors in style.css). The most @@ -1249,6 +1269,8 @@ def main(argv): build_index() elif len(argv) == 2 and argv[1] == "apps": build_apps_index() + elif len(argv) == 2 and argv[1] == "content": + build_content() elif len(argv) == 3 and argv[1] == "ci": name = argv[2] if public_repo(name): diff --git a/server/install.sh b/server/install.sh index 3617376..be55591 100755 --- a/server/install.sh +++ b/server/install.sh @@ -26,7 +26,6 @@ ln -sfn ~/fw/tools/server/fw ~/bin/fw site=~/code.fuzzyworld.net cp ~/fw/tools/server/site/htaccess "$site/.htaccess" cp ~/fw/tools/server/site/style.css ~/fw/tools/server/site/robots.txt ~/fw/tools/server/site/404.html "$site/" -mkdir -p "$site/why" && cp ~/fw/tools/server/site/why/index.html "$site/why/" mkdir -p "$site/contribute" && cp ~/fw/tools/server/site/contribute/index.html "$site/contribute/" mkdir -p "$site/principles" && cp ~/fw/tools/server/site/principles/index.html "$site/principles/" apps=~/apps.fuzzyworld.net @@ -34,6 +33,7 @@ cp ~/fw/tools/server/site-apps/htaccess "$apps/.htaccess" cp ~/fw/tools/server/site/style.css "$apps/" ~/bin/fw install-hooks ~/bin/fw apps-index +~/bin/fw content # Scheduled jobs: replace only our own block in the crontab, keeping anything else. chmod +x ~/fw/tools/server/jobs/*.sh { { crontab -l 2>/dev/null || true; } | sed '/^# fw:begin/,/^# fw:end/d'; cat ~/fw/tools/server/jobs/crontab; } | crontab - diff --git a/server/site/why/index.html b/server/site/why/index.html deleted file mode 100644 index 205f2f4..0000000 --- a/server/site/why/index.html +++ /dev/null @@ -1,44 +0,0 @@ -<!doctype html> -<html lang="en"> - -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Why this site exists · code.fuzzyworld.net</title> - <link rel="stylesheet" href="/style.css"> -</head> - -<body> - <header class="site"><a class="home" href="/">code.fuzzyworld.net</a></header> - <main> - <h1>Why I left GitLab</h1> - <p> - On Monday, October 26, 2026, I came back to work after a week's vacation to Friday Harbor. While on vacation I did what I like to do for fun and made a turn-based rogue-like Bomberman clone. - So back at work, I was thinking of sharing it with some coworkers, - but very quickly GitLab showed me a "Rate limit exceeded" error. And I rapidly learned that GitLab enacted - some rate-limiting policies recently that blocked repo access at work, and, very quickly, even - access to GitLab itself!</p> - <p>So yeah, I couldn't look at my personal code at work, and that pissed me off, and now all of my code and - projects are hosted on Dreamhost, where I already keep a blog and a lightweight webpage.</p> - <ul> - <li>code: <a href="https://code.fuzzyworld.net/">https://code.fuzzyworld.net/</a> - </li> - <li>apps: <a href="https://apps.fuzzyworld.net/">https://apps.fuzzyworld.net/</a></li> - </ul> - <p>No rate limiting, no sign-in, no "modern" limits. This is a static website! What more do I really need?</p> - <p></p> - <p>I'm currently trying to formalize the process of the move from GitLab to Dreamhost, and eventually my - learnings are going to be at /how/ on this website.</p> - - <h2>Principles</h2> - <p>Things made with AI should be shared freely with the world. The code and apps here were made with - AI, so they are MIT-licensed: use them, change them, share them.</p> - <p>My conversations with the AI are different. My words and my way of working are mine. I publish a - conversation only when I choose to, I can take that permission back, and nobody may copy my words or - my style of work without my express permission.</p> - <p>More on the <a href="/principles/">principles</a> page.</p> - </main> - <footer class="site"><a href="/">All repositories</a> · <a href="https://apps.fuzzyworld.net/">Apps</a> · <a href="/principles/">Principles</a></footer> -</body> - -</html> \ No newline at end of file