diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 5008ddf..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.github/workflows/demon.yml b/.github/workflows/demon.yml
new file mode 100644
index 0000000..21e853b
--- /dev/null
+++ b/.github/workflows/demon.yml
@@ -0,0 +1,62 @@
+name: Maxwell's Demon
+
+on:
+ issues:
+ types: [opened]
+
+concurrency:
+ group: demon-state
+ cancel-in-progress: false
+
+permissions:
+ contents: write
+ issues: write
+
+jobs:
+ sort:
+ if: "startsWith(github.event.issue.title, 'demon: sort 12 bits')"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Sort 12 bits into the lattice
+ run: |
+ python3 - <<'EOF'
+ import datetime
+ import json
+
+ path = "state/demon.json"
+ with open(path) as fh:
+ state = json.load(fh)
+ state["bits_sorted"] += 12
+ state["generation"] += 1
+ state["demons"] += 1
+ state["last_sorted_at"] = datetime.datetime.now(
+ datetime.timezone.utc
+ ).isoformat(timespec="seconds")
+ with open(path, "w") as fh:
+ json.dump(state, fh, indent=2)
+ fh.write("\n")
+ EOF
+ python3 engine/generate_entropy_svg.py
+
+ - name: Commit lowered entropy
+ env:
+ AUTHOR: ${{ github.event.issue.user.login }}
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "41898470+github-actions[bot]@users.noreply.github.com"
+ git add state/demon.json assets/entropy.svg
+ git commit -m "chore: demon sorted 12 bits (S lowered by @${AUTHOR})"
+ git pull --rebase origin "${GITHUB_REF_NAME}"
+ git push
+
+ - name: Thank the demon and close the gate
+ env:
+ GH_TOKEN: ${{ github.token }}
+ ISSUE: ${{ github.event.issue.number }}
+ run: |
+ gh issue comment "$ISSUE" --repo "$GITHUB_REPOSITORY" --body \
+ "12 bits sorted. Entropy of this README decreased by 34.4 zJ (12 × kT ln 2 at 300 K). The second law remains statistical. Thank you, demon."
+ gh issue edit "$ISSUE" --repo "$GITHUB_REPOSITORY" --add-label demon
+ gh issue close "$ISSUE" --repo "$GITHUB_REPOSITORY"
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 0000000..21cb5f0
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,37 @@
+name: Nightly Telemetry
+
+on:
+ schedule:
+ - cron: "17 6 * * *"
+ workflow_dispatch:
+
+concurrency:
+ group: demon-state
+ cancel-in-progress: false
+
+permissions:
+ contents: write
+
+jobs:
+ refresh:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Refresh feed, stats, featured cards, entropy field
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: python3 engine/nightly.py
+
+ - name: Commit if changed
+ run: |
+ if git diff --quiet; then
+ echo "no changes"
+ exit 0
+ fi
+ git config user.name "github-actions[bot]"
+ git config user.email "41898470+github-actions[bot]@users.noreply.github.com"
+ git add README.md state/demon.json assets/entropy.svg
+ git commit -m "chore: nightly telemetry refresh"
+ git pull --rebase origin "${GITHUB_REF_NAME}"
+ git push
diff --git a/.github/workflows/snake.yml b/.github/workflows/snake.yml
index 81849ab..988375b 100644
--- a/.github/workflows/snake.yml
+++ b/.github/workflows/snake.yml
@@ -4,19 +4,15 @@ on:
schedule:
# Runs every 12 hours
- cron: "0 */12 * * *"
-
+
workflow_dispatch:
-
- push:
- branches:
- - main
jobs:
generate:
runs-on: ubuntu-latest
permissions:
contents: write
-
+
steps:
- name: Generate Snake
uses: Platane/snk/svg-only@v3
@@ -25,11 +21,11 @@ jobs:
outputs: |
dist/github-contribution-grid-snake.svg
dist/github-contribution-grid-snake-dark.svg?palette=github-dark
-
+
- name: Push to output branch
uses: crazy-max/ghaction-github-pages@v4
with:
target_branch: output
build_dir: dist
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2348c91
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+__pycache__/
+*.pyc
diff --git a/CLAUDE.md b/CLAUDE.md
index 45c2fb1..9b4b58f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -4,23 +4,33 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Repository Overview
-This is a GitHub profile repository containing only a README.md file that displays on the @developtheweb GitHub profile page. There is no source code, build configuration, or tests in this repository.
+This is the GitHub profile repository for @developtheweb. Its README renders on the profile page and is a live system, not a static page: an animated entropy-reversal SVG whose state is lowered by visitors ("Maxwell's demon"), plus nightly-refreshed telemetry. Do not reintroduce third-party rendering services (capsule-render, readme-typing-svg, komarev, vercel stats/quotes apps) — everything renders from this repo, GitHub, or stevenmilanese.com assets.
-## Repository Structure
+## Architecture
```
-/home/aurelius/git/developtheweb/
-└── README.md
+README.md profile page; contains marker-fenced generated sections
+engine/generate_entropy_svg.py SMIL-animated assets/entropy.svg from state/demon.json (stdlib only)
+engine/nightly.py refreshes README marker sections + bumps entropy generation (stdlib only)
+state/demon.json bits_sorted / generation / demons / last_sorted_at
+assets/entropy.svg generated — never hand-edit; regenerate via the engine
+.github/workflows/demon.yml issues:opened, title "demon: sort 12 bits" → +12 bits, regen SVG, commit, comment, close
+.github/workflows/nightly.yml cron 17 6 * * * → engine/nightly.py, commit if changed
+.github/workflows/snake.yml cron every 12h → contribution snake SVGs on the `output` branch
```
-## Working with this Repository
+## README marker sections (machine-written — edit the generators, not the sections)
-Since this is a profile repository with only a README.md file:
+- `` — 4 newest Strange Quarks articles (RSS `/feed.xml` if populated, else parsed from https://stevenmilanese.com/blog HTML)
+- `` — telemetry row with live star/repo totals
+- `` — featured cards (anthropic-certs, slTrain, meowchi-releases, mpl) with live star counts
-- Any changes should maintain the professional formatting and structure of the profile README
-- The README uses GitHub-flavored markdown with centered content, badges, and images
-- External image assets are referenced from `https://github.com/developtheweb/stevenmilanese-com/blob/main/public/`
+`engine/nightly.py` is fail-safe per section: on fetch/parse failure it leaves that section untouched and exits 0.
-## Note
+## Conventions
-This is not a development project - it's a GitHub profile repository used for personal branding and showcasing work. There are no build commands, tests, or development workflows associated with this repository.
\ No newline at end of file
+- Conventional commit messages (`feat:`, `fix:`, `chore:`, `ci:`). No attribution footers of any kind.
+- Contact is `rev@moonfactory.dev` only — the old Telegram link and the old level-host email address are retired and must not reappear.
+- Entropy formula: `S = max(12.7, 100 − 0.0002·bits_sorted)`; 12 bits per demon click = 34.4 zJ (12 × kT ln 2 at 300 K).
+- SVG regeneration is deterministic for a given `generation` — diffs stay reviewable.
+- Test locally with `python3 engine/generate_entropy_svg.py` and `GITHUB_TOKEN=$(gh auth token) python3 engine/nightly.py` (both stdlib-only; no pip installs).
diff --git a/README.md b/README.md
index 47ffd49..b0ea0d3 100644
--- a/README.md
+++ b/README.md
@@ -1,191 +1,120 @@
-
-
+# Reversing the irreversible
-
-
+*Rev. Steven Milanese — the second law is statistical, not sacred. The demon pays its bills in bits.*
-
- [](https://git.io/typing-svg)
-
-
-
-
-
-
-
-
+
+
+ [⚡ Be the demon — sort 12 bits](https://github.com/developtheweb/developtheweb/issues/new?title=demon%3A+sort+12+bits&body=One+tap.+Submit+to+sort.)
+
+ Each click opens a one-tap issue; an Action sorts the field, recommits the SVG, closes the issue. This README's state is community-lowered entropy.
-
-
-
-
-
-
+## About the Reverend
-## 🎯 About Me
-
-```python
-class StevenMilanese:
- def __init__(self):
- self.title = "Autodidactic Polymath | Systems Alchemist"
- self.location = "🌍 Earth"
- self.os = "Arch Linux BTW 🐧"
- self.current_focus = ["AI Architecture", "Quantum Computing", "WebGL", "Spiritual Tech"]
- self.philosophy = "Bridge technical excellence with human experience"
-
- def transform_challenges(self, problem):
- return f"✨ Inspired solution for {problem}"
+```
+Reverend ≔ Physicist ⊗ Minister ⊗ Systems_Alchemist
+domain : ℝ³·¹ ⊗ CY₃(χ = ±6)
+axiom : complexity ⟼ elegance
+method : ∀ p ∈ Inconceivable — solve(p) ∨ pose(better_p)
+runtime : Arch Linux, btw
```
-I transform complex challenges into inspired technological solutions. By seamlessly integrating Artificial Intelligence with cutting-edge development practices, I create systems that push the boundaries of what's possible. My expertise spans multiple domains including theoretical physics, mathematics, AI systems architecture, and spiritual technology.
+*Written in MPL — the author's own language. Ordained minister, autodidactic polymath, natural philosopher. The ministry and the physics are the same inquiry conducted at different energy scales.*
-## 🚀 Tech Arsenal
+## The mission — goals inconceivable by design
+
+
+
+
+**Reverse the irreversible**
+
+Maxwell's demon on GitHub's own infrastructure, funded in Landauer's currency. *(running above)*
+
+
+
+
+**Derive the three generations**
+
+Calabi–Yau compactifications, χ = ±6. [ORCID](https://orcid.org/0009-0008-0442-208X) · [OSF](https://osf.io/3tsd4/) · [companion essays](https://stevenmilanese.com/blog/tag/calabi-yau-manifolds)
+
+
+
+
+
+
+**Cognitive universality**
+
+[MPL](https://github.com/developtheweb/mpl): if you can write the equation, you can run it.
+
+
+
+
+**Planetary intelligence**
+
+Earth as information processor, argued in full on [Strange Quarks](https://stevenmilanese.com/blog/planetary-intelligence-earth-as-information-processor).
+
+
+
+
+
+
-### Languages & Frameworks
-
-
-
-
-
-
-
-
-### Operating System & Environment
-
-
-
-
-
-### Tools & Technologies
-
-
-
-
-
-
-
+`10¹⁰⁶ yr until heat death — the deadline` · `2.9 zJ of order per bit sorted (kT ln 2, 300 K)` · `★ 27 stars across 14 public repos`
+
-## 📊 GitHub Analytics
+## Beneath the physics — the verified inventory
+
diff --git a/assets/entropy.svg b/assets/entropy.svg
new file mode 100644
index 0000000..ecb6ae4
--- /dev/null
+++ b/assets/entropy.svg
@@ -0,0 +1,126 @@
+
diff --git a/engine/generate_entropy_svg.py b/engine/generate_entropy_svg.py
new file mode 100644
index 0000000..c053295
--- /dev/null
+++ b/engine/generate_entropy_svg.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+"""Generate assets/entropy.svg — a SMIL-animated entropy-reversal field.
+
+120 particles loop from a seeded chaos cloud into a (2,5) torus-knot
+lattice, hold, and scatter back. State (bits sorted by visitors, chaos
+generation) comes from state/demon.json. Stdlib only; deterministic for
+a given generation so regenerated output is diffable.
+"""
+
+import hashlib
+import json
+import math
+import os
+import sys
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+STATE_PATH = os.path.join(ROOT, "state", "demon.json")
+OUT_PATH = os.path.join(ROOT, "assets", "entropy.svg")
+
+WIDTH, HEIGHT = 880, 260
+MARGIN = 20
+N_PARTICLES = 120
+KNOT_R, KNOT_r = 150, 58
+DUR = "11s"
+KEY_TIMES = "0;0.64;0.82;1"
+KEY_SPLINES = "0.25 0.1 0.25 1;0 0 1 1;0.55 0 0.45 1"
+
+BG = "#010409"
+BORDER = "#21262d"
+CYAN = "#4dd4e8"
+DEEP = "#1d6f7d"
+GREEN = "#7ee2a8"
+MUTED = "#8b949e"
+
+
+def seeded_unit(index, generation, channel):
+ """Deterministic float in [0, 1) from particle index + generation."""
+ digest = hashlib.sha256(f"{index}:{generation}:{channel}".encode()).digest()
+ return int.from_bytes(digest[:8], "big") / 2**64
+
+
+def knot_points(n):
+ """(2,5) torus knot sampled at n points, scaled/centered to the canvas."""
+ raw = []
+ for i in range(n):
+ t = 2 * math.pi * i / n
+ rad = KNOT_R + KNOT_r * math.cos(5 * t)
+ raw.append((rad * math.cos(2 * t), 0.62 * rad * math.sin(2 * t)))
+ xs, ys = [p[0] for p in raw], [p[1] for p in raw]
+ span_x, span_y = max(xs) - min(xs), max(ys) - min(ys)
+ scale = min((WIDTH - 2 * MARGIN) / span_x, (HEIGHT - 2 * MARGIN) / span_y)
+ cx, cy = (max(xs) + min(xs)) / 2, (max(ys) + min(ys)) / 2
+ return [
+ (WIDTH / 2 + (x - cx) * scale, HEIGHT / 2 + (y - cy) * scale)
+ for x, y in raw
+ ]
+
+
+def main():
+ with open(STATE_PATH) as fh:
+ state = json.load(fh)
+ bits = int(state.get("bits_sorted", 0))
+ generation = int(state.get("generation", 0))
+ entropy = max(12.7, 100 - 0.0002 * bits)
+ s_label = f"{entropy:.1f}"
+
+ lattice = knot_points(N_PARTICLES)
+ parts = [
+ f'")
+
+ svg = "\n".join(parts) + "\n"
+ os.makedirs(os.path.dirname(OUT_PATH), exist_ok=True)
+ with open(OUT_PATH, "w") as fh:
+ fh.write(svg)
+ size = os.path.getsize(OUT_PATH)
+ print(f"wrote {OUT_PATH} ({size} bytes, S={s_label}, bits={bits}, gen={generation})")
+ if size > 200 * 1024:
+ print("error: SVG exceeds 200 KB budget", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/engine/nightly.py b/engine/nightly.py
new file mode 100644
index 0000000..9a2f04b
--- /dev/null
+++ b/engine/nightly.py
@@ -0,0 +1,264 @@
+#!/usr/bin/env python3
+"""Nightly telemetry refresh for the profile README.
+
+Updates the marker-fenced sections of README.md:
+ FEED — 4 newest Strange Quarks articles (RSS if populated, else the
+ server-rendered blog HTML)
+ STATS — telemetry row with live star/repo totals
+ FEATURED — star counts on the featured project cards
+and bumps the entropy field's chaos generation so the field differs daily.
+
+Every section is fail-safe: if a fetch or parse fails, that section is left
+untouched and the script still exits 0. Stdlib only.
+"""
+
+import datetime
+import html as htmllib
+import json
+import os
+import re
+import subprocess
+import sys
+import urllib.request
+import xml.etree.ElementTree as ET
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+README = os.path.join(ROOT, "README.md")
+STATE_PATH = os.path.join(ROOT, "state", "demon.json")
+
+SITE = "https://stevenmilanese.com"
+# The real feed. /feed.xml was a guess that 404'd for weeks while the HTML
+# fallback silently matched nothing, so the FEED table quietly froze; it now
+# also 301s here, but point at the canonical URL rather than lean on that.
+FEED_URL = f"{SITE}/rss.xml"
+BLOG_URL = f"{SITE}/blog"
+# The site publishes read-time in its own namespace — valid for strict parsers,
+# unambiguous for this one.
+MANUSCRIPT_NS = "https://stevenmilanese.com/ns/manuscript"
+
+FEATURED_REPOS = [
+ ("anthropic-certs", "Verified Anthropic certifications — Claude, API, Claude Code CLI, MCP."),
+ ("slTrain", "A steam locomotive for your terminal, smoke trail included."),
+ ("meowchi-releases", "A desktop pet that evolves when you actually get work done."),
+ ("mpl", "Mathematics Programming Language — write the equation, run the equation."),
+]
+
+
+def fetch(url, accept=None):
+ req = urllib.request.Request(url, headers={"User-Agent": "developtheweb-nightly/1.0"})
+ if accept:
+ req.add_header("Accept", accept)
+ token = os.environ.get("GITHUB_TOKEN")
+ if token and url.startswith("https://api.github.com"):
+ req.add_header("Authorization", f"Bearer {token}")
+ with urllib.request.urlopen(req, timeout=30) as resp:
+ return resp.read().decode("utf-8", errors="replace")
+
+
+def gh_api(path):
+ return json.loads(fetch(f"https://api.github.com{path}", accept="application/vnd.github+json"))
+
+
+def replace_section(text, marker, body):
+ start, end = f"", f""
+ if start not in text or end not in text:
+ raise ValueError(f"missing {marker} markers")
+ pre = text.split(start)[0]
+ post = text.split(end)[1]
+ return f"{pre}{start}\n{body}\n{end}{post}"
+
+
+def articles_from_rss():
+ """Primary source: the site's real feed.
+
+ The feed carries read-time in the site's own namespace, so the meta column
+ comes from the publisher rather than being scraped back out of a page.
+ """
+ root = ET.fromstring(fetch(FEED_URL))
+ items = []
+ for item in root.iter("item"):
+ title = (item.findtext("title") or "").strip()
+ link = (item.findtext("link") or "").strip()
+ pub = (item.findtext("pubDate") or "").strip()
+ date = None
+ try:
+ date = datetime.datetime.strptime(pub[:16].strip(), "%a, %d %b %Y")
+ except ValueError:
+ pass
+ mins = (item.findtext(f"{{{MANUSCRIPT_NS}}}readingMinutes") or "").strip()
+ meta = f"{mins} min read" if mins.isdigit() else ""
+ if title and link:
+ items.append({"title": title, "url": link, "date": date, "meta": meta})
+ return items
+
+
+def articles_from_html():
+ """Fallback: parse the blog index.
+
+ Written against the Manuscript's markup, which is regular enough not to
+ need heuristics — each entry is a `row` div holding one anchor and one
+ `meta` span:
+
+
+
+ The previous version looked for a thumbnail `alt=` attribute and a
+ Title-Case date. The redesign has neither — no feature images on the index
+ and uppercase abbreviated months — so it matched nothing and silently
+ returned an empty list for weeks.
+ """
+ page = fetch(BLOG_URL)
+ skip = ("/blog/tag/", "/blog/author/")
+ articles, seen = [], set()
+
+ row_re = re.compile(
+ r']+href="(/blog/[a-z0-9][a-z0-9-]*)"[^>]*>(.*?)'
+ r'.{0,400}?]*class="meta"[^>]*>(.*?)',
+ re.S,
+ )
+ for m in row_re.finditer(page):
+ slug, raw_title, raw_meta = m.group(1), m.group(2), m.group(3)
+ if slug.startswith(skip) or slug in seen:
+ continue
+
+ title = htmllib.unescape(re.sub(r"<[^>]+>", "", raw_title)).strip()
+ meta_text = htmllib.unescape(re.sub(r"<[^>]+>", " ", raw_meta))
+ meta_text = re.sub(r"\s+", " ", meta_text).strip()
+
+ # "JUL 28, 2025" — uppercase, abbreviated month.
+ date_m = re.search(r"([A-Za-z]{3,}) (\d{1,2}), (\d{4})", meta_text)
+ if not (title and date_m):
+ continue
+ month, day, year = date_m.groups()
+ date = None
+ for fmt in ("%b %d %Y", "%B %d %Y"):
+ try:
+ date = datetime.datetime.strptime(f"{month.title()} {day} {year}", fmt)
+ break
+ except ValueError:
+ continue
+ if date is None:
+ continue
+
+ mins_m = re.search(r"(\d+)\s*MIN", meta_text, re.I)
+ seen.add(slug)
+ articles.append({
+ "title": title,
+ "url": f"{SITE}{slug}",
+ "date": date,
+ "meta": f"{mins_m.group(1)} min read" if mins_m else "",
+ })
+ return articles
+
+
+def update_feed(text):
+ articles = []
+ try:
+ articles = articles_from_rss()
+ except Exception as exc:
+ print(f"::warning title=nightly FEED rss::rss unusable ({exc}); falling back to html")
+ if not articles:
+ print("::warning title=nightly FEED fallback::rss yielded nothing; scraping /blog")
+ articles = articles_from_html()
+ dated = [a for a in articles if a["date"]]
+ dated.sort(key=lambda a: a["date"], reverse=True)
+ newest = dated[:4]
+ if len(newest) < 4:
+ raise ValueError(f"only {len(newest)} parseable articles")
+ rows = ["| Article | |", "|:---|---:|"]
+ for a in newest:
+ title = a["title"].replace("|", "\\|")
+ when = a["date"].strftime("%b %d, %Y").replace(" 0", " ")
+ meta = f"{when} · {a['meta']}" if a["meta"] else when
+ rows.append(f"| [{title}]({a['url']}) | {meta} |")
+ return replace_section(text, "FEED", "\n".join(rows))
+
+
+def update_stats(text):
+ repos = gh_api("/users/developtheweb/repos?per_page=100&type=owner")
+ public = [r for r in repos if not r["private"]]
+ stars = sum(r["stargazers_count"] for r in public)
+ line = (
+ "
\n\n"
+ "`10¹⁰⁶ yr until heat death — the deadline` · "
+ "`2.9 zJ of order per bit sorted (kT ln 2, 300 K)` · "
+ f"`★ {stars} stars across {len(public)} public repos`\n\n"
+ "
"
+ )
+ return replace_section(text, "STATS", line)
+
+
+def update_featured(text):
+ cards = []
+ for name, blurb in FEATURED_REPOS:
+ repo = gh_api(f"/repos/developtheweb/{name}")
+ cards.append(
+ f'
'
+ )
+ return replace_section(text, "FEATURED", table)
+
+
+def bump_entropy():
+ with open(STATE_PATH) as fh:
+ state = json.load(fh)
+ state["generation"] += 1
+ with open(STATE_PATH, "w") as fh:
+ json.dump(state, fh, indent=2)
+ fh.write("\n")
+ subprocess.run(
+ [sys.executable, os.path.join(ROOT, "engine", "generate_entropy_svg.py")],
+ check=True,
+ )
+
+
+def warn(label, exc):
+ """Fail-safe, but never quiet.
+
+ Every section still degrades to 'leave it alone and exit 0' — a broken
+ fetch must not wedge the profile. What changed is visibility: a section
+ that stops updating now announces itself as a GitHub Actions warning
+ annotation, which surfaces in the run summary instead of scrolling past in
+ a log nobody opens. The FEED table sat frozen for 37 days precisely
+ because a silent skip and a successful run looked identical.
+ """
+ print(f"::warning title=nightly {label} skipped::{label} left untouched — {exc}")
+ print(f"{label}: left untouched ({exc})", file=sys.stderr)
+
+
+def main():
+ with open(README) as fh:
+ text = fh.read()
+ failures = 0
+ for label, fn in (("FEED", update_feed), ("STATS", update_stats), ("FEATURED", update_featured)):
+ try:
+ text = fn(text)
+ print(f"{label}: updated")
+ except Exception as exc:
+ failures += 1
+ warn(label, exc)
+ with open(README, "w") as fh:
+ fh.write(text)
+ try:
+ bump_entropy()
+ print("ENTROPY: regenerated")
+ except Exception as exc:
+ failures += 1
+ warn("ENTROPY", exc)
+ if failures:
+ print(f"::warning title=nightly incomplete::{failures} of 4 sections did not update")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/state/demon.json b/state/demon.json
new file mode 100644
index 0000000..e154670
--- /dev/null
+++ b/state/demon.json
@@ -0,0 +1,6 @@
+{
+ "bits_sorted": 12,
+ "generation": 52,
+ "demons": 1,
+ "last_sorted_at": "2026-07-08T02:02:03+00:00"
+}