diff --git a/.forgejo/workflows/main.yaml b/.forgejo/workflows/main.yaml
new file mode 100644
index 0000000..78facd9
--- /dev/null
+++ b/.forgejo/workflows/main.yaml
@@ -0,0 +1,18 @@
+on: [push]
+jobs:
+ job:
+ container:
+ image: ${{vars.DOCKER}}debian:bookworm
+ steps:
+ - name: spcd
+ env:
+ SPCD: ${{vars.SPCD}}
+ SPCD_SSH_HOSTS: ${{vars.SPCD_SSH_HOSTS}}
+ SPCD_SSH_KEY: ${{secrets.SPCD_SSH_KEY}}
+ SPCD_TXT_LOCALE: ${{vars.SPCD_TXT_LOCALE}}
+ run: ${{vars.SPCD}}
+
+ - run: spcd-check-project
+ - run: spcd-build-project
+ - run: spcd-browse-workspace
+ - run: spcd-synchronize
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e2e7327
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/out
diff --git a/build.py b/build.py
new file mode 100755
index 0000000..81ffcd9
--- /dev/null
+++ b/build.py
@@ -0,0 +1,41 @@
+#! /usr/bin/env python3
+"""Build web."""
+
+from pathlib import Path
+
+from rwx.fs import make_directory, read_file_text, write
+from rwx.ps import run
+
+if __name__ == "__main__":
+ root = Path(__file__).parent
+ out = root / "out" / "web"
+ gv = root / "index.gv"
+ svg = out / "index.svg"
+ make_directory(out)
+ run("dot", str(gv), "-Tsvg", "-o", str(svg))
+ text = read_file_text(svg)
+ write(
+ out / "index.css",
+ """\
+html {
+background-color: #202020;
+}
+""",
+ )
+ write(
+ out / "index.html",
+ f"""\
+
+
+
+
+
+todo.rwx.work
+
+
+
+{text}
+
+
+""",
+ )
diff --git a/index.gv b/index.gv
new file mode 100644
index 0000000..c0e938a
--- /dev/null
+++ b/index.gv
@@ -0,0 +1,264 @@
+digraph "index" {
+bgcolor="transparent"
+color="#C0C000"
+fontcolor="#FF8000"
+fontname="DejaVu Sans"
+penwidth="2"
+rankdir="RL"
+
+edge [
+fontcolor="#FF4040"
+fontname="DejaVu Sans"
+style="filled"
+]
+
+node [
+color="#C0C0C0"
+fontcolor="#FFFFFF"
+fontname="DejaVu Sans"
+penwidth="2"
+style="filled"
+]
+
+{ rank="max"
+"" [style="invis"]
+}
+
+edge [color="#008000"]
+node [fillcolor="#408040"]
+
+subgraph "cluster/dev" { label="Dev"
+"plan" [label="Plan"]
+"code" [label="Code"]
+"build" [label="Build"]
+"test" [label="Test"]
+}
+
+"plan" -> "code" -> "build" -> "test" -> {
+"plan"
+"release"
+}
+
+subgraph "cluster/ops" { label="Ops"
+"release" [label="Release"]
+"deploy" [label="Deploy"]
+"operate" [label="Operate"]
+"monitor" [label="Monitor"]
+}
+
+"release" -> "deploy" -> "operate" -> "monitor" -> {
+"deploy"
+"plan"
+}
+
+edge [color="#FF0000"]
+node [fillcolor="#303030"]
+
+subgraph "cluster/social" {
+label="Social"
+
+subgraph "cluster/social/corp" {
+label="Corp"
+
+"social/corp/discord" [
+fontcolor="#8080FF"
+label="Discord"
+URL="https://discord.gg/v6p7CtZ4Zh"
+]
+
+"social/corp/instagram" [
+fontcolor="#8080FF"
+label="InstaGram"
+URL="https://instagram.com/marc.beninca"
+]
+
+"social/corp/linkedin" [
+fontcolor="#8080FF"
+label="LinkedIn"
+URL="https://linkedin.com/in/marc-beninca"
+]
+
+"social/corp/youtube" [
+fontcolor="#8080FF"
+label="YouTube"
+URL="https://youtube.com/@marc.beninca"
+]
+
+}
+
+subgraph "cluster/social/open" {
+label="Open"
+
+"social/open/bluesky" [
+fontcolor="#8080FF"
+label="BlueSky"
+URL="https://bsky.app/profile/marc.beninca.link"
+]
+
+subgraph "cluster/social/open/keyoxide" {
+label="KeyOxide"
+
+"social/open/keyoxide/pgp" [
+fontcolor="#8080FF"
+label="PGP"
+URL="https://keyoxide.org/08EDA7006234A0EB29A3A8471DBD5EC4BADA5579"
+]
+
+"social/open/keyoxide/asp" [
+fontcolor="#8080FF"
+label="ASP"
+URL="https://keyoxide.org/aspe:keyoxide.org:WUD5YVN52J3RJ6CD4ZCWYL6S54"
+]
+
+}
+
+}
+
+}
+
+subgraph "cluster/beninca.link" {
+label="beninca.link"
+URL="https://beninca.link"
+
+"beninca.link/marc" [
+fontcolor="#8080FF"
+label="Marc"
+URL="https://marc.beninca.link"
+]
+
+}
+
+subgraph "cluster/rwx.work" {
+label="rwx.work"
+URL="https://rwx.work"
+
+"rwx.work/blog" [
+fontcolor="#8080FF"
+label="Blog"
+URL="https://blog.rwx.work"
+]
+
+"rwx.work/forge" [
+fontcolor="#8080FF"
+label="Forge"
+URL="https://forge.rwx.work"
+]
+
+"rwx.work/ilos" [
+fontcolor="#8080FF"
+label="ILOS:\nIncremental Live\nOperating System"
+URL="https://ilos.rwx.work"
+]
+
+"rwx.work/lsgm" [
+fontcolor="#8080FF"
+label="LSGM:\nLive Scan\nGrub Menu"
+URL="https://lsgm.rwx.work"
+]
+
+"rwx.work/ofsp" [
+fontcolor="#8080FF"
+label="OFSP:\nOperating File\nSystem Profile"
+URL="https://ofsp.rwx.work"
+]
+
+"rwx.work/prj" [
+fontcolor="#8080FF"
+label="PRJ:\nPRJ"
+URL="https://prj.rwx.work"
+]
+
+"rwx.work/rtfd" [
+fontcolor="#8080FF"
+label="RTFD:\nRead The\nFancy Docs"
+URL="https://rtfd.rwx.work"
+]
+
+subgraph "cluster/rwx.work/rwx" {
+label="RWX:\nRead Write eXecute"
+URL="https://rwx.rwx.work"
+
+"rwx.work/rwx/python" [label="Python"]
+"rwx.work/rwx/shell" [label="Shell"]
+
+}
+
+"rwx.work/spcd" [
+fontcolor="#8080FF"
+label="SPCD:\nShell to Python\nContinuous Deployment"
+URL="https://spcd.rwx.work"
+]
+
+"rwx.work/srmp" [
+fontcolor="#8080FF"
+label="SRMP:\nSoftware Repositories\nMirror Profile"
+URL="https://srmp.rwx.work"
+]
+
+"rwx.work/todo" [
+fontcolor="#8080FF"
+label="TODO:\nTO\nDO"
+URL="https://todo.rwx.work"
+]
+
+}
+
+"rwx.work/forge/marc" [
+fontcolor="#8080FF"
+label="Marc"
+URL="https://forge.rwx.work/marc.beninca"
+]
+"rwx.work/forge/marc" -> "rwx.work/forge"
+
+{
+"ofsp/python" [label="Python"]
+"ofsp/shell" [label="Shell"]
+} -> "rwx.work/ofsp"
+
+{
+"rtfd/forgejo" [label="Forgejo"]
+} -> "rwx.work/rtfd"
+
+{
+"rwx/ffmpeg" [label="FFMPEG"]
+"rwx/gource" [label="Gource"]
+"rwx/logo" [label="Logo"]
+} -> "cluster/rwx.work/rwx"
+
+{
+"rwx/python/codium" [label="Codium"]
+"rwx/python/freetube" [label="FreeTube"]
+"rwx/python/venvs" [label="Build VEnvs"]
+} -> "rwx.work/rwx/python"
+{
+"rwx/shell/cs" [label="CryptSetup"]
+"rwx/shell/venv" [label="Use VEnv"]
+} -> "rwx.work/rwx/shell"
+
+{
+"srmp/alma" [label="Alma"]
+"srmp/debian" [label="Debian"]
+"srmp/docker" [label="Docker"]
+"srmp/msys" [label="MSys"]
+"srmp/pypi" [label="PyPI"]
+"srmp/python" [label="Python"]
+} -> "rwx.work/srmp"
+
+{
+"srmp/debian/codium" [label="Codium"]
+"srmp/debian/incus" [label="Incus"]
+} -> "srmp/debian"
+
+subgraph "cluster/tilde.link" {
+label="tilde.link"
+URL="https://tilde.link"
+
+"tilde.link/tm" [
+fontcolor="#8080FF"
+label="TM:\nTrack Mania"
+URL="https://tm.tilde.link"
+]
+
+}
+
+}
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..2c784a4
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,49 @@
+# Track Ongoing DevOps
+
+A graph to track things to do.
+
+---
+
+## Why
+
+Dependencies between tasks of projects.
+
+---
+
+## How
+
+A tree to identify leafs.
+
+---
+
+## What
+
+Generate:
+
+* [X] SVG with GraphViz
+* [X] HTML including SVG
+
+---
+
+## Authors
+
+* [Marc Beninca](https://marc.beninca.link)
+
+---
+
+## Where
+
+### Chat
+
+* [Discord](https://discord.com/channels/983145051985154108/1315476519325274112)
+* [IRC](ircs://irc.libera.chat/#todo)
+
+### Forge
+
+* [Repository](https://forge.rwx.work/rwx.work/todo)
+* [RSS](https://forge.rwx.work/rwx.work/todo.rss)
+* [Workflows](https://forge.rwx.work/rwx.work/todo/actions)
+
+### Deployment
+
+* [Site](https://todo.rwx.work)