{"id":35847391,"url":"https://github.com/ratherlargerobot/uriel","last_synced_at":"2026-02-03T06:05:51.996Z","repository":{"id":142787511,"uuid":"567541840","full_name":"ratherlargerobot/uriel","owner":"ratherlargerobot","description":"A minimalistic, stable, feature complete python3 static site generator","archived":false,"fork":false,"pushed_at":"2025-11-19T00:41:51.000Z","size":445,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-19T02:25:08.769Z","etag":null,"topics":["extensible","feature-complete","html","minimalistic","python3","ssg","stable","static-site","static-site-generation","static-site-generator","web","webdevelopment"],"latest_commit_sha":null,"homepage":"https://nathanrosenquist.com/uriel/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ratherlargerobot.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-18T02:20:32.000Z","updated_at":"2025-11-19T00:29:50.000Z","dependencies_parsed_at":"2025-08-31T02:35:39.894Z","dependency_job_id":null,"html_url":"https://github.com/ratherlargerobot/uriel","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/ratherlargerobot/uriel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratherlargerobot%2Furiel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratherlargerobot%2Furiel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratherlargerobot%2Furiel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratherlargerobot%2Furiel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ratherlargerobot","download_url":"https://codeload.github.com/ratherlargerobot/uriel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratherlargerobot%2Furiel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29035414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T02:28:16.591Z","status":"ssl_error","status_checked_at":"2026-02-03T02:27:48.904Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["extensible","feature-complete","html","minimalistic","python3","ssg","stable","static-site","static-site-generation","static-site-generator","web","webdevelopment"],"created_at":"2026-01-08T06:19:21.207Z","updated_at":"2026-02-03T06:05:51.990Z","avatar_url":"https://github.com/ratherlargerobot.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# uriel\n\nBy Nathan Rosenquist\n\n[https://nathanrosenquist.com/uriel/](https://nathanrosenquist.com/uriel/)\n\n## Overview\n\nYet another static site generator.\n\nNamed for the archangel Uriel in the novel Unsong, whose job was to perform\nthe fantastic and mundane work necessary to keep the world functioning.\n\n## Installation\n\nuriel is a single, standalone Python script. You can just run the script from\nany directory, as any user, without installing it or requiring root\nprivileges. You can even copy it into your project directory, so it stays\nwith the project.\n\nIf you want to install it in a centralized location for all users on a\nmachine:\n\n```bash\nsudo make install\n```\n\n## Usage\n\n```bash\nuriel \u003cproject-root\u003e\n```\n\nIf the project root is a directory that does not exist, it will be created and\ninitialized with new project files. Subsequent invocations of the uriel\ncommand against the project root will regenerate the static files of the web\nsite from the project files.\n\n## Organization and Structure\n\nThe project root has the following top-level directories:\n\n- **`templates/`** - templates to merge with dynamic content\n- **`nodes/`** - dynamic content nodes to merge with templates\n- **`lib/`** - user-defined Python code\n- **`static/`** - static content to copy to the web site unmodified\n- **`public/`** - rendered web site\n\n## Templates\n\nTemplates support substitution parameters:\n\n### `include`\n\n_Syntax:_\n```\n{{ include : \u003ctemplate\u003e }}\n```\n\n_Example:_\n```\n{{include:some_template_name.html}}\n```\n\nThe template name is a file in the templates directory. Includes are recursive.\n\n### `value`\n\n_Syntax:_\n```\n{{ value : \u003cparameter-name\u003e }}\n```\n\n_Example:_\n```\n{{value:title}}\n```\n\nThe named parameter is pulled out of the Node headers. For example, if a\ndynamic node has a \"Title: Foo\" header, then the example above resolves to\n\"Foo\".\n\nYou can make up any parameter name you want, set it in the node headers, and\nreference it in the templates or nodes as a substitution parameter.\n\nThe value is HTML escaped.\n\n### `value-unescaped`\n\n_Syntax:_\n```\n{{ value-unescaped : \u003cparameter-name\u003e }}\n```\n\n_Example:_\n```\n{{value-unescaped:title}}\n```\n\nIdentical to the `{{value:foo}}` substitution parameter, but the value is not\nHTML escaped.\n\n### `breadcrumbs`\n\n_Syntax:_\n```\n{{ breadcrumbs : * }}\n```\n\n_Example:_\n```\n{{breadcrumbs:*}}\n```\n\nPrints out HTML breadcrumb navigation links for the node.\n\n### `created`\n\n_Syntax:_\n```\n{{ created : \u003cstrftime-format-string\u003e }}\n```\n\n_Example:_\n```\n{{created:%B %d, %Y}}\n```\n\nPrints out the node creation date using the format string.\n\n### `modified`\n\n_Syntax:_\n```\n{{ modified : \u003cstrftime-format-string\u003e }}\n```\n\n_Example:_\n```\n{{modified:%B %d, %Y}}\n```\n\nPrints out the node modification date using the format string.\n\n### `static-url`\n\n_Syntax:_\n```\n{{ static-url : \u003ctarget-url-path\u003e }}\n```\n\n_Examples:_\n```\n{{static-url:foo.jpg}}\n{{static-url:/favicon.ico}}\n{{static-url:/foo/bar/quux.jpg}}\n```\n\nPrints out the URL for the target file.\n\nIf a path is specified without a leading slash, it is relative to the location\nof the URL of the node on the site.\n\nIf a path is specified with a leading slash, it is specified relative to the\npublic root of the site.\n\nNote that directory traversal via `../` is not allowed. However, specifying a\nfile in a subdirectory via `foo/bar.jpg` is allowed.\n\nThe benefit of referring to a static URL using this approach is that, if the\ntarget path is not found on the filesystem, this will generate a visible error\nwhen you try to build the site.\n\n### `static-hash-url`\n\n_Syntax:_\n```\n{{ static-hash-url : \u003ctarget-url-path\u003e }}\n```\n\n**Examples:**\n```\n{{static-hash-url:foo.css}}\n{{static-hash-url:/css/main.css}}\n{{static-hash-url:/css/photos/gallery.css}}\n```\n\nCauses the target file to be copied to a dynamically generated copy of the\nfile in the same directory, using a hash of the file contents as the file\nname. For example, if `/css/main.css` is the target path, and\n`md5sum css/main.css` hashes to `\"d41d8cd98f00b204e9800998ecf8427e\"`, then a\nfile named `css/d41d8cd98f00b204e9800998ecf8427e.css` will be generated the\nfirst time this parameter is referenced, and the URL path returned will be to\n`/css/d41d8cd98f00b204e9800998ecf8427e.css`.\n\nThe point of this is to force web browsers to load a new version of the file\nwhen the content changes. Recommended for CSS and JavaScript files to avoid\nbrowser caching issues.\n\n### `rss`\n\n_Syntax:_\n```\n{{ rss : url }}\n```\n\n_Example:_\n```\n{{rss:url}}\n```\n\nPrints out the canonical RSS URL.\n\n### `node:body`\n\n_Syntax:_\n```\n{{ node : body }}\n```\n\n_Example:_\n```\n{{node:body}}\n```\n\nIncludes the body portion of a node in the template.\n\n### `node:url`\n\n_Syntax:_\n```\n{{ node : url }}\n```\n\n_Example:_\n```\n{{node:url}}\n```\n\nPrints out the URL for the current node.\n\n### `node:name`\n\n_Syntax:_\n```\n{{ node : name }}\n```\n\n_Example:_\n```\n{{node:name}}\n```\n\nPrints out the name of the current node, e.g. (index, foo).\n\n### `node:title`\n\n_Syntax:_\n```\n{{ node : title }}\n```\n\n_Example:_\n```\n{{node:title}}\n```\n\nPrints out the value of the \"Title\" header for the current node, or a display\nformatted version of the node name if the title is not set.\n\n### `node:link`\n\n_Syntax:_\n```\n{{ node : link }}\n```\n\n_Example:_\n```\n{{node:link}}\n```\n\nPrints out an HTML text link to the current node, using its title.\n\n### `node-url`\n\n_Syntax:_\n```\n{{ node-url : \u003ctarget-node-path\u003e }}\n```\n\n_Example:_\n```\n{{node-url:foo/bar}}\n```\n\nPrints out the URL for the target node.\n\n### `node-name`\n\n_Syntax:_\n```\n{{ node-name : \u003ctarget-node-title\u003e }}\n```\n\n_Example:_\n```\n{{node-name:foo/bar}}\n```\n\nPrints out the name for the target node (e.g. bar).\n\n### `node-title`\n\n_Syntax:_\n```\n{{ node-title : \u003ctarget-node-title\u003e }}\n```\n\n_Example:_\n```\n{{node-title:foo/bar}}\n```\n\nPrints out the value of the \"Title\" header for the target node, or the node\nname if title is not set.\n\n### `node-link`\n\n_Syntax:_\n```\n{{ node-link : \u003ctarget-node-path\u003e }}\n```\n\n_Example:_\n```\n{{node-link:foo/bar}}\n```\n\nPrints out an HTML text link to the target node, using its title.\n\n### `node-list`\n\n_Syntax:_\n```\n{{ node-list : * }}\n```\n\n_Example:_\n```\n{{node-list:*}}\n```\n\nList all of the child nodes underneath the current node, with links to their\nURLs, using the node titles.\n\nNodes are sorted so that the newest nodes are listed first.\n\nMore precisely, the sort order is:\n- created time descending\n- modified time descending\n- title ascending\n- url ascending\n\nAll nodes have modified times, but nodes only have created times if the\nCreated header is explicitly set. If nodes are compared and some of them have\ncreated times and others don't, the sort ordering will preferentially try\ncreated times, but compare them to modified times if that's all that is\navailable.\n\n### `tag-list`\n\n_Syntax:_\n```\n{{ tag-list : * }}\n```\n\n_Example:_\n```\n{{tag-list:*}}\n```\n\nA value of `*` lists all of the tags that are relevant to the node or\ntemplate. This is context sensitive.\n\nIn the Tag-Node (e.g. the root of the tag index), this parameter will list all\nof the tags in alphabetical order, with links to virtual nodes for each tag\nthat exists.\n\nIn the virtual nodes under the tag node, this parameter will list all of the\npages associated with that tag, in descending order by date.\n\nOn a regular node that is not the Tag-Node or one of its virtual children,\nthis parameter will list all of the tags that the given node references in the\nTags header.\n\n### `soju`\n\n_Syntax:_\n```\n{{ soju : \u003cpython-code-in-soju-module\u003e }}\n```\n\n_Example:_\n```\n{{soju:hello(node)}}\n```\n\n`lib/soju.py` is a Python module that allows user-defined handlers to run\nduring parameter substitution.\n\nThe rvalue for this parameter will be executed as a function in the soju\nmodule. The user-defined function is expected to return a string, which will\nbe included in the output in place of the substitution parameter.\n\nFor example, this substitution parameter:\n```\n{{soju:foo()}}\n```\n\nGets turned into this when it is called:\n```python\nsoju.foo()\n```\n\nThe following symbols are exported into the soju module at runtime:\n\n- **`uriel`** - The uriel module\n- **`SojuError`** - Exception class that soju functions can raise if you want\n  to cause an error, but don't need a stack trace.\n- **`log(s)`** - log method. Logs the string to stderr, and prepends it with\n  \"soju: \" to help identify the source of the error during troubleshooting.\n- **`escape(s)`** - Accepts an unescaped string, and returns an HTML escaped\n  string.\n\nThe following symbols are available to pass into soju functions as arguments\nfrom within nodes and templates:\n\n- **`page`** - A reference to the uriel Page instance calling this code.\n- **`node`** - A reference to the uriel Node instance being rendered.\n- **`project_root`** - Path to the project root directory.\n- **`use_canonical_url`** - Boolean indicating whether canonical URLs are\n  enabled in the current context. Generally canonical URLs are not enabled\n  when rendering the main pages on the site, but are enabled when rendering\n  the RSS feed.\n\nThe return value from a soju function is not HTML escaped. Any content that\nneeds to be HTML escaped should be run through the `escape()` function.\n\n## Nodes\n\nNodes contain dynamic content to merge with templates.\n\nThis is the content of your site, that gets merged with the templates.\n\nThe format of a node file is similar to HTTP or email. It optionally contains\nheaders of the form \"Key: value\", one per line, followed by a blank line,\nfollowed by the body contents of the node.\n\nHeaders are converted to lowercase internally, and can be referenced in\ntemplates using the `{{ value : \u003cheader-name\u003e }}` substitution parameter. You\ncan make up your own headers, and reference them in nodes and templates. For\nexample, if you set this header on a node:\n\n```\nFoo: bar\n```\n\nThen you can reference that value later in a node or template like so:\n\n```\n{{value:foo}}\n```\n\nIn the example above, the `{{value:foo}}` substitution parameter would\nevaluate to \"bar\" when the site is generated.\n\nAll headers are inherited by child nodes, unless overridden by the child\nnodes. For example, setting a \"Foo: bar\" header in the index node will cause\n`{{value:foo}}` to evaluate to \"bar\" in every node on the site, unless\noverridden at a lower level.\n\nThere are also some headers that are treated specially. While they can also\nbe used as values, other parts of the system recognize them.\n\n### Special Headers\n\n| Header | Purpose |\n|--------|---------|\n| **Title** | Sets the title of the node, as returned by the `{{node:title}}` and `{{node-title:\u003cnode-path\u003e}}` parameters.\u003cbr\u003e\u003cbr\u003eAs a special case, the \"Title\" is not inherited by child nodes, because titles should not all be identical by default.\u003cbr\u003e\u003cbr\u003eIf the title is not set, a default title is created based on the node name. |\n| **Created** | Explicitly sets the time a node was created. If set, must be in ISO 8601 format. There is no default value.\u003cbr\u003e\u003cbr\u003eThe GNU `date` command has an ISO 8601 formatting option (`date -Iseconds` or `date -Is`).\u003cbr\u003e\u003cbr\u003eThe BSD `date` command does not have an ISO 8601 formatting option. You can get the date and time (without the time zone) in ISO 8601 format using `date +%FT%T`. |\n| **Modified** | Explicitly sets the time a node was modified. If set, must be in ISO 8601 format. If not set, the mtime on the node file will be used instead.\u003cbr\u003e\u003cbr\u003eSee documentation for the \"Created\" header for additional hints about formatting the date. |\n| **Escape-Title** | If set, this header controls whether the value of the Title header should be automatically escaped. \"true\" and \"false\" are the only valid settings (without quotes). The default value is true. |\n| **Template** | Specifies the template to use to render the node.\u003cbr\u003e\u003cbr\u003eIf not specified, the default.html template is used.\u003cbr\u003e\u003cbr\u003eIf the value of template is set to \"null\", then no template will be used (unless a template called \"null\" is created under the templates directory). |\n| **Format** | If set to \"text\", node page body will have `\u003cbr\u003e` tags appended to the end of each line. |\n| **Breadcrumb-Separator** | If set, this value will be used as a separator in HTML breadcrumbs. The default value is \"\u0026raquo;\" (without quotes). |\n| **Breadcrumb-Separator-Spaces** | If set, this header controls whether spaces are included between breadcrumbs and breadcrumb separators. \"true\" and \"false\" are the only valid settings (without quotes). The default value is true. |\n| **Flat-URL** | If set, this header controls whether the URL for a node is flat (at the top level of the site), or whether it is placed in a directory matching its node path. \"true\" and \"false\" are the only valid settings. The default value is false. |\n| **Link-Prefix** | HTML to include before every link in an automatically generated list of tags or nodes. The default is \"`\u003cp\u003e`\". |\n| **Link-Suffix** | HTML to include after every link in an automatically generated list of tags or nodes. The default is \"`\u003c/p\u003e`\". |\n| **Tags** | Optional comma-separated list of tags for a node. The node will be included in an auto-generated tag index for each tag it is associated with. |\n| **Tag-Node** | Defines the file-based node which will serve as the root of the dynamically generated tag links.\u003cbr\u003e\u003cbr\u003eThis only has an effect when it is set on the root node. If this is not set, the tag index will not be created. |\n| **Canonical-URL** | The canonical URL for the web site, without the path portion, e.g. https://www.example.com |\n| **RSS-URL** | The relative URL path to use when generating the RSS feed, relative to the root of the site, e.g. /rss.xml\u003cbr\u003e\u003cbr\u003eIf this is not set, the RSS feed will not be generated.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Title** | Title to use in the RSS feed. If not set, the \"Title\" header from the root node will be used instead.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Description** | Description text to include in the RSS feed.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Image-URL** | The relative or absolute URL to use for the RSS image to present as the icon for this site.\u003cbr\u003e\u003cbr\u003eOptional.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Image-Width** | The width of the RSS image.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Image-Height** | The height of the RSS image.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **RSS-Include** | If set, this header controls whether a node is eligible for inclusion in the RSS feed. \"true\" and \"false\" are the only valid settings. The default value is false. |\n| **RSS-Add-Node-Title-Header** | If set, the node title will be included as an HTML `\u003ch1\u003e` header before the node body in the RSS description. \"true\" and \"false\" are the only valid settings. The default value is true. |\n| **Sitemap-URL** | The relative URL path to use when generating the sitemap XML file, relative to the root of the site, e.g. /sitemap.xml\u003cbr\u003e\u003cbr\u003eA sitemap can only list URL paths that are at or below its level, so it is recommended to put it in the root directory.\u003cbr\u003e\u003cbr\u003eThis must be set on the root node to have any effect. |\n| **Sitemap-Include** | If set, this header controls whether a node is eligible for inclusion in the sitemap. \"true\" and \"false\" are the only valid settings. The default value is true. |\n\n### Header Inheritance and Modification\n\nIf you want to remove a header that was inherited from a parent node, simply\ninclude the header on the current node, prefixed with a \"-\", with a value of\n\"*\". For example, if the parent node had a header of the form:\n\n```\nFoo: bar\n```\n\nyou could remove this header in the child node by setting it as follows:\n\n```\n-Foo: *\n```\n\nYou can also set a header so that it doesn't take effect in the current node,\nbut will take effect in child nodes. For example, imagine you had a node\ncalled `articles/index`, and then a bunch of nodes under `articles/` that had\ncontent (e.g. `articles/some-article`, `articles/some-other-thing`). You might\nwant to have the `articles/index` page use one template, but have all of the\nindividual articles use a different template, without having to set it on\nevery single article.\n\nTo set a header not in the current node, but only in its child nodes, prepend\na \"+\" sign to the name of the template. For example:\n\n```\n+Template: template-for-child-nodes.html\n```\n\nIt is also possible to stack layers of + and - prefixes, where each one will\nget processed in turn as the node tree is created. It is also possible to use\ntoo much magic and create a situation that is hard to reason about. If this\nsounds like you, experiment with it and see.\n\n### URL Generation\n\nEach node gets a unique URL path. If a unique URL path does not exist\nunambiguously, one of the conflicting nodes must be renamed. See the Flat-URL\nparameter to influence whether the node gets a straight mapping into a URL\npath hierarchy, or is promoted up to the top level of the site.\n\nA node named \"index\" takes on the URL of its containing directory. A node\nnamed anything else has its name mapped to a URL path.\n\nThe resulting URLs are all directories, each containing an \"index.html\" file\nthat can be served up as the default document by a web server.\n\n## Static Content\n\nStatic content to merge into the rendered web site, without modification.\n\nWhen uriel runs, the public directory is initialized to only contain the\nstatic content, completely overwriting and deleting whatever was in the public\ndirectory before.\n\nNext, the dynamic content is written. The rendered pages, RSS feed, sitemap,\netc.\n\nFinally, the static content is copied over again, but this time it will only\noverwrite any conflicting content in the public directory.\n\n## Public\n\nThe public directory contains the rendered web site, ready to be hosted on a\nweb server. Each dynamic node is rendered into an index.html file in its own\ndirectory. This makes the URLs a bit nicer and more abstract.\n\nAfter the dynamic nodes are generated in the public website directory, the\nstatic content is copied over, without modification.\n\n## User-Defined Python Code\n\nThe uriel program provides a basic, stable platform for hacking. It is\nentirely possible to build a complete website without any user-defined code.\nHowever, if you want to go deeper, there are numerous opportunities for\nsite-specific customization.\n\nWhen a project is created, the following files are created under the project\nroot:\n\n- `lib/soju.py`\n- `lib/handlers.py`\n\nSoju is where you can define arbitrary Python functions that can be\ninterpreted in substitution parameters in nodes and templates.\n\nThe handlers allow you to tap into various points during execution of the\nprogram, to insert your own code at several critical moments. You can add\ndynamically-generated pages that will be included in the generated site,\noverwrite built-in uriel functions with your own replacements, and all sorts\nof things.\n\nIf you want to heavily customize your site, hacking on these files is the way\nto go. You can import arbitrary Python modules, run arbitrary code, and\nbasically improve the system beyond recognition.\n\nThe core of uriel is not likely to change much. It does not have any external\ndependencies beyond python3. Goals for the core program include minimalism,\nsimplicity, stability, and longevity. I want this to still work 20 years from\nnow.\n\nBy providing these extension mechanisms, an individual site can customize\nvirtually everything about the system. Think of the core program as being a\nstable platform for modding, or a jazz standard that is begging to be\nreinterpreted.\n\nThis is also another way of saying that the feature set for the core uriel\nprogram is more or less set in stone, modulo any bug fixes. If you write your\nown Python code that replaces the built-in method to generate the RSS feed,\nfor example, my fervent hope is that it will continue to work indefinitely,\nwithout any surprises.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fratherlargerobot%2Furiel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fratherlargerobot%2Furiel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fratherlargerobot%2Furiel/lists"}