Recently Written · git

tiny-runlevels

Using an init system for many instances of simple programs . https://therealtruex.com/posts/Using-an-init-system-for-many-instances-of-simple-programs

git clone https://github.com/equwal/tiny-runlevels

Log | Files | Refs


commit 2e3715ee8bffc95f39383510e9b5374be1ad3280
Spenser Truex <truex@equwal.com>
2025-09-07 11:52:57 -0700

Initial commit

 .aim/memory.jsonl              |   0
 .mcp.json                      | 566 +++++++++++++++++++++++++++++++++++++++++
 README.md                      |  97 +++++++
 restart-runlevel               |   5 +
 services/irc/libera_onechannel |   1 +
 services/quark/quark_onefolder |   1 +
 tiny-runlevels                 |   1 +
 7 files changed, 671 insertions(+)
diff --git a/.aim/memory.jsonl b/.aim/memory.jsonl
new file mode 100644
index 0000000..e69de29
diff --git a/.mcp.json b/.mcp.json
new file mode 100644
index 0000000..c74c483
--- /dev/null
+++ b/.mcp.json
@@ -0,0 +1,566 @@
+{
+  "mcpServers": {
+    "permissions": {
+      "auto_approved_tools": [
+        "memory",
+        "read-website-fast",
+        "duckduckgo", 
+        "arxiv",
+        "hacker-news",
+        "sequential-thinking",
+        "llm-context",
+        "file-merger",
+        "everything-search",
+        "markitdown",
+        "mcpmcp",
+        "1mcp-agent",
+        "magg",
+        "open-library",
+        "manim-server",
+        "blender-mcp",
+        "bazi-mcp",
+        "quran-mcp",
+        "metmuseum-mcp",
+        "playwright-executeautomation",
+        "apple-reminders",
+        "youtube-transcript",
+        "playwright-microsoft",
+        "mcp-browser-kit",
+        "apple-shortcuts",
+        "aws-pricing-mcp",
+        "books-mcp-server", 
+        "node-code-sandbox-mcp",
+        "mcp-server-leetcode",
+        "codemcp",
+        "leetcode-mcp-server",
+        "code-to-tree",
+        "serena",
+        "code-assistant",
+        "maxmsp-mcp-server",
+        "vertex-developer",
+        "mcp-server-notify",
+        "opendata-mcp",
+        "dicom-mcp",
+        "mongodb-lens",
+        "mcp-sqlite",
+        "mcp-server-duckdb",
+        "mongo-mcp",
+        "prisma-mcp",
+        "mcp-server-qdrant",
+        "quarkus-jdbc",
+        "redis-mcp-server",
+        "mcp-alchemy",
+        "aseprite-mcp",
+        "oorlogsbronnen-server",
+        "anilist-mcp"
+      ],
+      "require_permission": [
+        "desktop-commander",
+        "docker",
+        "taskwarrior",
+        "playwright",
+        "playwright-executeautomation",
+        "apple-reminders",
+        "youtube-transcript",
+        "playwright-microsoft",
+        "mcp-browser-kit",
+        "apple-shortcuts"
+      ],
+      "claude_tools": {
+        "auto_approved": {
+          "read_operations": [
+            "Read",
+            "Glob", 
+            "Grep",
+            "WebFetch",
+            "WebSearch"
+          ],
+          "bash_read_only": [
+            "ls",
+            "cat",
+            "grep",
+            "find",
+            "head",
+            "tail",
+            "wc",
+            "file",
+            "stat",
+            "pwd",
+            "whoami",
+            "date",
+            "ps",
+            "top",
+            "df",
+            "du",
+            "which",
+            "whereis"
+          ]
+        },
+        "require_permission": {
+          "write_operations": [
+            "Write",
+            "Edit",
+            "MultiEdit",
+            "NotebookEdit"
+          ],
+          "bash_write_operations": [
+            "mkdir",
+            "touch",
+            "cp", 
+            "mv",
+            "rm",
+            "chmod",
+            "chown",
+            "git",
+            "npm",
+            "pip",
+            "cargo",
+            "make",
+            "docker",
+            "systemctl",
+            "service"
+          ]
+        }
+      }
+    },
+    "memory": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mcp-knowledge-graph",
+        "--memory-path",
+        "/home/jose/.config/claude-desktop/.aim/memory.jsonl"
+      ]
+    },
+    "read-website-fast": {
+      "type": "stdio", 
+      "command": "npx",
+      "args": [
+        "-y",
+        "@just-every/mcp-read-website-fast"
+      ]
+    },
+    "desktop-commander": {
+      "type": "stdio",
+      "command": "npx", 
+      "args": [
+        "-y",
+        "@wonderwhy-er/desktop-commander"
+      ]
+    },
+    "sequential-thinking": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@modelcontextprotocol/server-sequential-thinking"
+      ]
+    },
+    "taskwarrior": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y", 
+        "mcp-server-taskwarrior"
+      ]
+    },
+    "playwright": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@automatalabs/mcp-server-playwright"
+      ]
+    },
+    "duckduckgo": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "duckduckgo-mcp-server"
+      ]
+    },
+    "arxiv": {
+      "type": "stdio", 
+      "command": "npx",
+      "args": [
+        "-y",
+        "arxiv-mcp-server"
+      ]
+    },
+    "hacker-news": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mcp-hn"
+      ]
+    },
+    "docker": {
+      "type": "stdio",
+      "command": "npx", 
+      "args": [
+        "-y",
+        "mcp-server-docker"
+      ]
+    },
+    "mcpmcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": ["-y", "mcp-remote@latest", "https://mcpmcp.io/mcp"]
+    },
+    "llm-context": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "llm-context",
+        "lc-mcp"
+      ]
+    },
+    "file-merger": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@exoticknight/mcp-file-merger",
+        "/home/jose/.config/claude-desktop"
+      ]
+    },
+    "everything-search": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "mcp-server-everything-search"
+      ]
+    },
+    "markitdown": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "markitdown-mcp"
+      ]
+    },
+    "1mcp-agent": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@1mcp/agent"
+      ]
+    },
+    "magg": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "magg"
+      ]
+    },
+    "open-library": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@8enSmith/mcp-open-library"
+      ]
+    },
+    "manim-server": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "manim-mcp-server"
+      ]
+    },
+    "blender-mcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "blender-mcp"
+      ]
+    },
+    "bazi-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@cantian-ai/bazi-mcp"
+      ]
+    },
+    "quran-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "quran-mcp-server"
+      ]
+    },
+    "metmuseum-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "metmuseum-mcp"
+      ]
+    },
+    "playwright-executeautomation": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@executeautomation/playwright-mcp-server"
+      ]
+    },
+    "apple-reminders": {
+      "type": "stdio",
+      "command": "mcp-server-apple-reminders",
+      "args": []
+    },
+    "youtube-transcript": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@kimtaeyoon83/mcp-server-youtube-transcript"
+      ]
+    },
+    "playwright-microsoft": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "@playwright/mcp@latest"
+      ]
+    },
+    "mcp-browser-kit": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "@mcp-browser-kit/server"
+      ]
+    },
+    "apple-shortcuts": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mcp-server-apple-shortcuts"
+      ]
+    },
+    "aws-pricing-mcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/trilogy-group/aws-pricing-mcp",
+        "aws-pricing-mcp"
+      ]
+    },
+    "books-mcp-server": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from", 
+        "git+https://github.com/VmLia/books-mcp-server",
+        "books-mcp-server"
+      ]
+    },
+    "node-code-sandbox-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "node-code-sandbox-mcp"
+      ]
+    },
+    "mcp-server-leetcode": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@mcpfun/mcp-server-leetcode"
+      ]
+    },
+    "codemcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/ezyang/codemcp@prod",
+        "codemcp"
+      ]
+    },
+    "leetcode-mcp-server": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "@jinzcdev/leetcode-mcp-server"
+      ]
+    },
+    "code-to-tree": {
+      "type": "stdio",
+      "command": "code-to-tree",
+      "args": []
+    },
+    "serena": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "serena"
+      ]
+    },
+    "code-assistant": {
+      "type": "stdio",
+      "command": "code-assistant",
+      "args": []
+    },
+    "maxmsp-mcp-server": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/tiianhk/MaxMSP-MCP-Server",
+        "maxmsp-mcp-server"
+      ]
+    },
+    "vertex-developer": {
+      "type": "stdio",
+      "command": "developer",
+      "args": []
+    },
+    "mcp-server-notify": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "mcp-server-notify"
+      ]
+    },
+    "opendata-mcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/OpenDataMCP/OpenDataMCP",
+        "odmcp"
+      ]
+    },
+    "dicom-mcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "dicom-mcp"
+      ]
+    },
+    "mongodb-lens": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mongodb-lens"
+      ]
+    },
+    "mcp-sqlite": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mcp-sqlite",
+        "/tmp/example.db"
+      ]
+    },
+    "mcp-server-duckdb": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "mcp-server-duckdb",
+        "--db-path",
+        "/tmp/example.duckdb"
+      ]
+    },
+    "mongo-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "mongo-mcp",
+        "mongodb://localhost:27017/test"
+      ]
+    },
+    "prisma-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "prisma",
+        "mcp"
+      ]
+    },
+    "mcp-server-qdrant": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "mcp-server-qdrant"
+      ],
+      "env": {
+        "QDRANT_URL": "http://localhost:6333",
+        "COLLECTION_NAME": "default"
+      }
+    },
+    "quarkus-jdbc": {
+      "type": "stdio",
+      "command": "jbang",
+      "args": [
+        "jdbc@quarkiverse/quarkus-mcp-servers",
+        "jdbc:sqlite::memory:"
+      ]
+    },
+    "redis-mcp-server": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "redis-mcp-server",
+        "--url",
+        "redis://localhost:6379/0"
+      ]
+    },
+    "mcp-alchemy": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "mcp-alchemy",
+        "--with",
+        "sqlite",
+        "mcp-alchemy"
+      ],
+      "env": {
+        "DB_URL": "sqlite:///tmp/example.db"
+      }
+    },
+    "aseprite-mcp": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/diivi/aseprite-mcp",
+        "aseprite-mcp"
+      ]
+    },
+    "oorlogsbronnen-server": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "oorlogsbronnen-mcp"
+      ]
+    },
+    "anilist-mcp": {
+      "type": "stdio",
+      "command": "npx",
+      "args": [
+        "-y",
+        "anilist-mcp"
+      ]
+    }
+  }
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4985776
--- /dev/null
+++ b/README.md
@@ -0,0 +1,97 @@
+Using OpenRC runlevels to have lots of instances of simple (network)
+programs like quark for multiple http serving locally or ii (or sic)
+for IRC server connections.
+
+To keep programs simple, they should not do the same process for
+unrelated uses. It is much more complicated to configure and manage
+multiple webservers in the same process (like how nginx does it) than
+just one. Init systems are designed to manage processes, and should be
+used instead. Do one thing etc. etc.
+
+This is how to use the OpenRC runlevels for quark and ii runlevels
+as examples.
+
+## The Tree (on my machine)
+
+```sh
+/etc/runlevels
+├── boot
+│   └── ...
+├── default
+│   └── ...
+├── irc-base
+│   ├── oftc -> /etc/init.d/oftc
+│   ├── liberachat -> /etc/init.d/liberachat
+│   └── ...
+├── net-base
+│   ├── default -> ../default
+│   └── quark -> ../quark
+├── net-offline
+│   ├── default -> ../default
+│   └── net-base -> ../net-base
+├── net-dns
+│   ├── dnscrypt-proxy -> /etc/init.d/dnscrypt-proxy
+│   └── unbound -> /etc/init.d/unbound
+├── net-wifi
+│   ├── dhcpcd -> /etc/init.d/dhcpcd
+│   ├── net-base -> /etc/runlevels/net-base
+│   ├── net-dns -> /etc/runlevels/net-dns
+│   └── wpa_supplicant -> /etc/init.d/wpa_supplicant
+├── net-wifi-irc
+│   ├── irc-base -> ../irc-base
+│   └── net-wifi -> ../net-wifi
+├── quark
+│   ├── quark-docs -> /etc/init.d/quark-docs
+│   ├── quark-equwal -> /etc/init.d/quark-equwal
+│   └── ...
+├── shutdown
+│   └── ...
+└── sysinit
+    └── ...
+```
+as you can see, IRC is connected after the real internet on wifi
+(net-wifi), but quark runs on any network runlevel using net-base.
+
+## How To:
+
+OpenRC has its own commands for making the runlevels, but I find them
+confusing. Let's just edit the files.
+
+```sh
+# make runlevel
+mkdir /etc/runlevels/quark
+# add services (as many as needed)
+ln -s /etc/int.d/quark-whatever /etc/runlevels/quark
+# add runlevel to parent
+ln -s /etc/runlevels/default /etc/runlevels/quark
+# Reload since openrc is in default
+openrc default
+```
+
+That works, but what about for networked IRC on a custom networking runlevel? Just add it to the networking runlevel.
+```sh
+# (first, make a network runlevel that contains default! Without default the system will crash, obviously.)
+mkdir /etc/runlevels/net-wifi
+ln -s /etc/runlevels/net-wifi /etc/runlevels/default
+ln -s /etc/init.d/wpa_supplicant /etc/runlevels/net-wifi
+# etc.
+# Now add the irc-base to the network runlevel
+mkdir /etc/runlevels/irc-base
+ln -s /etc/init.d/liberachat irc-base
+ln -s /etc/init.d/oftc irc-base
+ln -s /etc/runlevels/irc-base /etc/runlevels/net-wifi
+openrc net-wifi
+```
+
+## Tool: restart-runlevel
+Openrc wants switch the whole stack `openrc runlevel` so I made a little
+tool to just restart a specific runlevel. Nice for debugging.
+
+```sh
+#!/bin/bash
+
+for link in /etc/runlevels/${1}/*
+do [[ -L "$link" && "$(readlink "$link")" == /etc/init.d/* ]] && \
+    rc-service "$(basename "$link")" restart
+done
+```
diff --git a/restart-runlevel b/restart-runlevel
new file mode 100755
index 0000000..ead27d5
--- /dev/null
+++ b/restart-runlevel
@@ -0,0 +1,5 @@
+#!/bin/bash
+for link in /etc/runlevels/${1}/*
+do [[ -L "$link" && "$(readlink "$link")" == /etc/init.d/* ]] && \
+    rc-service "$(basename "$link")" restart
+done
diff --git a/services/irc/libera_onechannel b/services/irc/libera_onechannel
new file mode 120000
index 0000000..6bd899f
--- /dev/null
+++ b/services/irc/libera_onechannel
@@ -0,0 +1 @@
+../../../ii-lchat-metapackage/services/lispirc
\ No newline at end of file
diff --git a/services/quark/quark_onefolder b/services/quark/quark_onefolder
new file mode 120000
index 0000000..32e6e43
--- /dev/null
+++ b/services/quark/quark_onefolder
@@ -0,0 +1 @@
+/etc/init.d/quark
\ No newline at end of file
diff --git a/tiny-runlevels b/tiny-runlevels
new file mode 100755
index 0000000..1a24852
--- /dev/null
+++ b/tiny-runlevels
@@ -0,0 +1 @@
+#!/bin/sh