{"id":16514867,"url":"https://github.com/schnatterer/rooted-graphene","last_synced_at":"2025-10-04T23:07:33.342Z","repository":{"id":213596732,"uuid":"734491847","full_name":"schnatterer/rooted-graphene","owner":"schnatterer","description":"GrapheneOS rooted and served via its own OTA server on GitHub pages","archived":false,"fork":false,"pushed_at":"2024-10-11T19:49:17.000Z","size":76,"stargazers_count":5,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-12T16:14:20.252Z","etag":null,"topics":["grapheneos","magisk","root","su"],"latest_commit_sha":null,"homepage":"https://schnatterer.github.io/rooted-graphene/","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/schnatterer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-12-21T20:28:05.000Z","updated_at":"2024-10-11T19:48:34.000Z","dependencies_parsed_at":"2024-08-04T04:27:52.644Z","dependency_job_id":"9311da10-3f92-455c-af41-b19839d9125d","html_url":"https://github.com/schnatterer/rooted-graphene","commit_stats":null,"previous_names":["schnatterer/rooted-graphene"],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnatterer%2Frooted-graphene","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnatterer%2Frooted-graphene/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnatterer%2Frooted-graphene/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnatterer%2Frooted-graphene/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schnatterer","download_url":"https://codeload.github.com/schnatterer/rooted-graphene/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238597388,"owners_count":19498396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["grapheneos","magisk","root","su"],"created_at":"2024-10-11T16:14:15.115Z","updated_at":"2025-10-04T23:07:33.330Z","avatar_url":"https://github.com/schnatterer.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"rooted-graphene\n===\n\nGrapheneOS over the air updates (OTAs) patched with Magisk allowing for AVB and locked bootloader *and* root access.  \nCan be upgraded over the air using [Custota](https://github.com/chenxiaolong/Custota) and its own OTA server.  \nAllows for switching between magisk and rootless via OTA upgrades.\n\n\u003e ⚠️ OS and root work in general. However, zygisk does not (and [likely never will](https://github.com/topjohnwu/Magisk/pull/7606)) \n\u003e work, leading to magisk being easily discovered by other apps and lots of banking apps not working.  \n See [below](#using-other-rooting-mechanisms) for alternatives.\n\n## Supported devices\n\nSee [rooted-graphene/ota | .github/workflows/release-multiple.yaml](https://github.com/rooted-graphene/ota/blob/main/.github/workflows/release-multiple.yaml).\n\nI plan to support as many devices as the GitHub Action limit allows for as long as this project is useful to me.\n\nIf you would like to see more devices, add them via PR to the file mentioned above.  \nAlternatively, it's easy to [set up your own builds](#setting-up-your-own-ota-builds), which also makes you the owner of the signing keys.\n\nIf this project is useful to you, please consider **[donating to GrapheneOS](https://grapheneos.org/donate)**.  \nPlease note that rooted-graphene is not an official GrapheneOS project.  \nAs they do most of the heavy lifting, I think they deserve every support they can get.\n\n## Notable changelog\n\nThese are only changes related to rooted-graphene, not GrapheneOS itself.  \nSee [grapheneos.org/releases](https://grapheneos.org/releases) for that.\n\n### [#173](https://github.com/schnatterer/rooted-graphene/pull/173), Sept 27, 2025\nRooted-graphene opts-in to use the `stable-security-preview`.\n\nBasically, this gets us security fixes a lot faster at the cost of patches not being open source at the moment of release.\n\nThe fact that rooted-graphene is patched into the original OTA binaries and not built from source makes this possible.\nIf you prefer staying with `stable` you can easily [set up your own builds](#setting-up-your-own-ota-builds) and set \n`OTA_CHANNEL` to `stable`.\n\nMore info: \n\u003e We're allowed to provide an early release with these patches and to list the CVEs but must wait until the embargo ends to publish sources or details on the patches.\n\u003e The positive side is that we can now provide patches to people who truly need them without even the previous 1 month embargo delay.\nhttps://grapheneos.org/releases#2025092500\n\n\u003e We do consider the security previews to be the normal and recommended choice.\nhttps://grapheneos.social/@GrapheneOS/115272851393143127\n\n### [#141](https://github.com/schnatterer/rooted-graphene/pull/141), July 10, 2025\n\nUpgrade to Custota 5.12, which contained a major regression where settings did not get migrated properly and got reset.\nUnfortunately, you will have to set the OTA URL again, to get the next update.\n\n[Fixed with Custota 5.13](https://github.com/chenxiaolong/Custota/blob/v5.13/CHANGELOG.md), 6dc6c4f on July 18, 2025.\n\n\u003e * Updating to this version will automatically restore the old settings without any manual intervention\n\u003e * If noticed your settings get reset in 5.12 and already reconfigured the app, your new settings will not be touched.\n\n### [#114](https://github.com/schnatterer/rooted-graphene/pull/114), May 22, 2025\n\nUpgrades to magisk 29. \n\nThere seems to be a bug that can occur with magisk updates and avbroot.\n\n[chenxiaolong/avbroot#455 (comment)](https://github.com/chenxiaolong/avbroot/issues/455#issuecomment-2955973508) \n\ncontains some approaches to troubleshooting.\nThis worked for me (at the expense of resetting Magisk's settings);\n```bash\nsu -c 'rm -r /data/adb/magisk* \u0026\u0026 reboot'\n```\n\nSee also [rooted-graphene#5](https://github.com/rooted-graphene/ota/issues/5).\n\n### 2025032500\n\nThe OTA builds moved into a separate GitHub organization to get full GitHub action minutes budget.  \nWith this, it is possible to add support for [devices discontinued lately](#2025030200) again 🥳.\n\n\u003e ⚠️ You need to change the OTA server url in custota app to either  \n\u003e https://rooted-graphene.github.io/ota/magisk  \n\u003e or  \n\u003e https://rooted-graphene.github.io/ota/rootless\n\nNote that the old URL https://schnatterer.github.io/rooted-graphene/ will no longer receive new OTAs soon.\n\nSome more details:\n* A GitHub organization has 2000 free GitHub Action Minutes per month.\n* Each device build takes 10 Minutes.\n* There are about 4 stable releases per month.\n* The budget should last for the current devices and even provide room to support more 🥳  \n\n### 2025030200\n\n* Discontinued some devices (Pixel 8 Pro (husky), Pixel 8 (shiba), Pixel 6a (bluejay)), because the amount of GitHub actions minutes required for \n  maintaining that many devices exceed my spending limit.  \n  Please fork this repo and build your own OTAs (see [Supported Devices](#supported-devices)).  \n  ![image](https://github.com/user-attachments/assets/11cf8fe9-b846-4979-8d7c-723408681354)\n* Switch from custota signature file version 1 to 2 (introduced with [custota 5](https://github.com/chenxiaolong/Custota/blob/v5.0/CHANGELOG.md) in october 2024)\n* If you're using custoa magisk module version \u003c 5, please upgrade.  \n  Even better: Delete custota magisk module, because it is now packaged in the OTA.\n\n### 2025021100\n* Start shipping custota app with OTA\n* This allows for OTA updates even when rootless and relieves you of the burden to keep the magisk module up to date.  \n  Starting with the next version, this will allow you to switch root and off by installing OTA updates!\n* In the `-magisk` flavor of rooted-graphene, the custota magisk module should be automatically disabled \n  on start. You can safely remove it. Custota is now a system app.\n* In the `-rootless` flavor the custota should be new, so no problems.  \n  Except when you had it installed as magisk module before (using the `-magisk` flavor).  \n  Then you should `adb sideload` the  `-magisk` first. Then custota should work as a system app.\n  Then you should be able to switch to `-rootless` with custota working.\n  Here are some troubleshooting tipps.\n  * test, if an upgrading works by long pressing `Version` in custota and then selecting `Allow reinstall`.  \n    This way you can also switch from `-magisk` to `-rootless` (and back if everything works as planned).\n  * you might have to change ownership or delete these files:\n    * `/sdcard/Android/data/com.chiller3.custota/`\n    * `/data/ota_packagecare_map.pb`\n  * If you no longer have root, you can always delete modules using `adb`, see [#82](https://github.com/schnatterer/rooted-graphene/issues/82).\n\n## Initial installation of OS\n\n### Hints \n* Make sure the versions of the unpatched version initially installed and the one taken from this repo match.\n* You might want to start with the version before the latest to try if OTA is working before initializing your device.\n* Don't mix up **factory image** and OTA\n* The following steps are basically the ones described at [avbroot](https://github.com/chenxiaolong/avbroot#initial-setup)\n  using the `avb_pkmd.bin` from [this repo](https://github.com/rooted-graphene/ota/).\n\n### Installation\n\nIt seems that [since 2025032500](https://github.com/schnatterer/rooted-graphene/issues/89) all first time installations (not the OTA updates later!) \nhave encountered an error on boot saying `Device is corrupt. It can't be trusted`.\n\nA lot of reports in the issues suggest that the most successful way to avoid it is to follow the instructions below \nuntil you encounter the error and then sideload the OTA *before* flashing custom keys. \n\nSee [this](https://github.com/schnatterer/rooted-graphene/issues/96#issuecomment-3128121844) and [that](https://github.com/schnatterer/rooted-graphene/issues/96#issuecomment-2986363782) comments for details.\n\n[Maybe it would be even simpler to just `adb sideload` the rooted-graphene OTA straight after GrapehenOS](https://github.com/schnatterer/rooted-graphene/issues/96#issuecomment-3128121844). If you are feeling courageous to try please report back via discussions or a PR to this README.\n\n⚠️ Please be aware that there is always some risk involved when flashing your device. \n It is unlikely but not unheard of to [hard brick](https://github.com/schnatterer/rooted-graphene/issues/96#issuecomment-3123443894) your device.\n If flashing fails, [**don't switch the slot**](https://github.com/schnatterer/rooted-graphene/issues/96#issuecomment-3128121844).\nPlease be careful. \nI just provide this software. \nUse it at your own risk. \n\n#### Install GrapheneOS\n\n##### Web Installer\n\nUsing the web installer is easier, but will always install the latest version. \nSo it's not possible to verify if OTA upgrades work right away.\n\nUse the [web installer](https://grapheneos.org/install/web) to install GrapheneOS:\n* Write down the installed version, e.g. `Downloaded caiman-install-2024123000.zip release`.\n* Stop at `Locking the bootloader` and close the browser. \n  We'll lock the bootloader later!\n\n##### Manual install\n\nAlternative method to Web installer.\n\nDownload [**factory image**](https://grapheneos.org/releases) and follow the [official instructions](https://grapheneos.org/install/cli)  to install GrapheneOS.\n\nTLDR:\n\n* Enable OEM unlocking\n* Obtain latest `fastboot`\n* Unlock Bootloader:\n  Enable usb debugging and execute `adb reboot bootloader`, or\n  \u003e The easiest approach is to reboot the device and begin holding the volume down button until it boots up into the bootloader interface.\n   ```shell\n   fastboot flashing unlock\n   ```\n* flash factory image\n\n  ```shell\n  bsdtar xvf DEVICE_NAME-factory-VERSION.zip # tar on windows and mac\n  ./flash-all.sh # or .bat on windows\n  ````\n* Stop after that and reboot (leave bootloader unlocked)\n\n#### Patch GrapheneOS with OTAs from this image\n\nOnce GrapheneOS is installed\n\n* Download the [OTA from releases](https://github.com/rooted-graphene/ota/releases) with **the same version** that you just installed. \n* Obtain latest `fastboot`\n* Install [avbroot](https://github.com/chenxiaolong/avbroot)\n* Extract the partition images from the patched OTA that are different from the original.\n    ```bash\n    avbroot ota extract \\\n        --input /path/to/ota.zip.patched \\\n        --directory extracted \\\n        --fastboot\n    ```\n* Set this environment variable to match the extracted folder:\n\n  For Linux/macOS:\n  ```bash\n  export ANDROID_PRODUCT_OUT=extracted\n  ```\n\n  For Windows (powershell):\n  ```powershell\n  $env:ANDROID_PRODUCT_OUT = \"extracted\"\n  ```\n  or (bat):\n  ```bat\n  set ANDROID_PRODUCT_OUT=extracted\n  ```\n\n* Flash the partitions using the command:\n  ```bash\n  fastboot flashall --skip-reboot\n  ```\n* Set up the custom AVB public key in the bootloader.\n    ```bash\n    fastboot reboot-bootloader\n    fastboot erase avb_custom_key\n    curl -s https://raw.githubusercontent.com/rooted-graphene/ota/refs/heads/main/avb_pkmd.bin \u003e avb_pkmd.bin\n    fastboot flash avb_custom_key avb_pkmd.bin\n    ```\n* **[Optional]** Before locking the bootloader, reboot into Android once to confirm that everything is properly signed.  \n   Install the Magisk or KernelSU app and run the following command:\n    ```bash\n    adb shell su -c 'dmesg | grep libfs_avb'\n    ```\n   If AVB is working properly, the following message should be printed out:\n    ```bash\n    init: [libfs_avb]Returning avb_handle with status: Success\n    ```\n* Reboot back into fastboot and lock the bootloader. This will trigger a data wipe again.\n    ```bash\n    fastboot flashing lock\n    ```\n* Confirm by pressing volume down and then power. Then reboot.\n* Remember: **Do not uncheck `OEM unlocking`!** (to avoid [hard-bricking](https://github.com/chenxiaolong/avbroot/blob/v3.12.0/README.md#warnings-and-caveats))  \n  That is, in Graphene's startup wizard, leave this box unticked 👇️  \n  \u003cimg src=\"https://github.com/schnatterer/rooted-graphene/assets/1824962/6ef90b46-2070-4d08-80d4-5f4a0e749cbe\" width=\"216\" height=\"480\" alt=\"Screenshot of GrapheneOS recommending to lock\"\u003e  \n  Note: The OTA contains [OEMUnlockOnBoot](https://github.com/chenxiaolong/OEMUnlockOnBoot), so OEM locking should be impossible.  \n  Still, better safe than sorry, keep it unlocked.\n\n#### Set up OTA updates\n\n* [Disable system updater app](https://github.com/chenxiaolong/avbroot#ota-updates).\n* Open Custota app and set the OTA server URL to point to this OTA server: https://rooted-graphene.github.io/ota/magisk\n\nAlternatively you could do updates manually via `adb sideload`:\n* reboot the device and begin holding the volume down button until it boots up into the bootloader interface\n* using volume buttons, toggle to recovery. Confirm by pressing power button\n* If the screen is stuck at a `No command` message, press the volume up button once while holding down the power button.\n* using volume buttons, toggle to `Apply update from ADB`. Confirm by pressing power button\n* `adb sideload xyz.zip`\n* See also [here](https://github.com/chenxiaolong/avbroot#updates).\n\n## Switching between root and rootless\n\nTo remove root, you can change to the \"rootless\" flavor.\n\nTo do so, set the following URL in custota: https://rooted-graphene.github.io/ota/rootless/\nAnd then upgrade.  \n(if custota should tell you that you're on the latest version, you can force an upgrade by long pressing `Version` and \nthen selecting `Allow reinstall`).\n\nIf you want to gain root again, just switch back to this URL in custota: https://rooted-graphene.github.io/ota/magisk/\nAnd then upgrade.\n\n## Magisk preinit strings\n\nSee [release-multiple.yaml](https://github.com/rooted-graphene/ota/blob/main/.github/workflows/release-multiple.yaml) for examples.\n\nHow to extract:\n\n* Get boot.img either from factory image or from OTA via\n  ```shell\n     avbroot ota extract \\\n     --input /path/to/ota.zip \\\n     --directory . \\\n     --boot-only\n  ```\n* Install magisk, patch boot.img, look for this string in the output:  \n  `Pre-init storage partition device ID: \u003cname\u003e`\n* Alternatively, extract from the patched boot.img: \n  ```shell\n  avbroot boot magisk-info \\\n  --image magisk_patched-*.img\n  ```\n* See also: https://github.com/chenxiaolong/avbroot/blob/master/README.md#magisk-preinit-device\n\n## Setting up your own OTA builds\n\n* Create your own keys `bash -c 'source rooted-ota.sh \u0026\u0026 generateKeys'` and store them in a dry and safe place.\n* Fork the [ota repo](https://github.com/rooted-graphene/ota) and add the following Repository secrets (`https://github.com/$YOU/$YOUR_REPO/settings/secrets/actions`)\n  * CERT_OTA_BASE64 (`base64 -w0 \u003c ota.crt`)\n  * KEY_AVB_BASE64 (`base64 -w0 \u003c avb.key`)\n  * KEY_OTA_BASE64 (`base64 -w0 \u003c ota.key`)\n  * PASSPHRASE_AVB (The passphrase for `avb.key`)\n  * PASSPHRASE_OTA (The passphrase for `ota.key`)\n* Uncomment or add your device(s) in `.github/workflows/release-multiple.yaml`\n  See [Magisk preinit string](#magisk-preinit-strings).\n\nThis sets up a cron job that builds the latest version of GrapheneOS, nightly.\n\nThis way, you won't have too many maintenance efforts but own your own signing key!  \nYou can also add a 3rd-party-magisk package if you're willing to trust the authors\n(see [Using other rooting mechanisms](#using-other-rooting-mechanisms)).\n\nAlternatively, search the forks if someone maintains the device of your choice.    \nBe aware that you would also have to trust them in addition to [me](https://github.com/schnatterer), [chenxiaolong](https://github.com/chenxiaolong) (the author of avbroot and Custota),\nthe authors of magisk, the authors of GrapheneOS, and the authors of the android open source project.\n\n## Script\n\nYou can use the `rooted-ota.sh` script in this repo to create your own OTAs and run your own OTA server.\n\n### Only create patched OTAs\n\n```shell\n# Generate keys\nbash -c 'source rooted-ota.sh \u0026\u0026 generateKeys'\n\n# Enter passphrases interactively\nDEVICE_ID=oriole MAGISK_PREINIT_DEVICE='metadata' bash -c '. rooted-ota.sh \u0026\u0026 createRootedOta'  \n \n# Enter passphrases via env (e.g. on CI)\n  export PASSPHRASE_AVB=1\n  export PASSPHRASE_OTA=1 \nDEVICE_ID=oriole MAGISK_PREINIT_DEVICE='metadata' bash -c '. rooted-ota.sh \u0026\u0026 createRootedOta' \n```\n\nFor IDs see [grapheneos.org/releases](https://grapheneos.org/releases). For Magisk preinit see,e.g. [here](#magisk-preinit-strings).\n\n### Upload patched OTAs as GH release and provide OTA server via GH pages\n\nSee GitHub actions for automating this:\n* [release single device](.github/workflows/release-single.yaml)\n* [release multiple devices](https://github.com/rooted-graphene/ota/blob/main/.github/workflows/release-multiple.yaml) regularly (using cron)\n\n```shell\nGITHUB_TOKEN=gh... \\\nGITHUB_REPO=schnatterer/rooted-graphene \\\nDEVICE_ID=oriole \\\nMAGISK_PREINIT_DEVICE=metadata \\\nbash -c '. rooted-ota.sh \u0026\u0026 createAndReleaseRootedOta'\n```\n\n### Using other rooting mechanisms\n\nAs [magisk does not seem a perfect match for GrapheneOS](https://github.com/topjohnwu/Magisk/pull/7606), you might be looking for alternatives.\n\nI had a first go at [patching kernelsu](https://github.com/schnatterer/rooted-graphene/commit/201b6dc939ab3a202694fa892de6db2840e5c3d6) which booted but did not provide root.\nPatching kernelsu is much more complex that patching magisk.\nIt might even be impossible to run GrapheneOS with it, without building GrapheneOS from scratch.\nAlso, some parts of kernelsu seem to be closed source, which feels suspicious and inappropriate for a tool with so much influence on your device.\n\nAnother alternative might be to use a version of magisk (like [the one maintained by pixincreate](https://github.com/pixincreate/Magisk)) that contains patches to make zygisk work.  \nThis still has some limitations, like [certain modules checking for magisk's signature won't work](https://github.com/schnatterer/rooted-graphene/commit/da0cd817c2665798df46df1aeb7caef9d98b79d0#r141746606).\n\nAnother option [might be](https://github.com/schnatterer/rooted-graphene/pull/73#issuecomment-2666870886) Kitsune magisk.\n\nIn general, using [magisk and especially zygisk with Graphene seems to have the risk of breaking things with every new release](https://github.com/chenxiaolong/avbroot/issues/213#issuecomment-1986637884).  \nIt's good to have the rootless version as a fallback!\n\n## Development\n```bash\n# DEBUG some parts of the script interactively\nDEBUG=1 bash --init-file rooted-ota.sh\n# Test loading secrets from env\nPASSPHRASE_AVB=1 PASSPHRASE_OTA=1 bash -c '. rooted-ota.sh \u0026\u0026 key2base64 \u0026\u0026 KEY_AVB=doesnotexist createAndReleaseRootedOta'        \n\n# Avoid having to download OTA all over again: SKIP_CLEANUP=true or:\nmkdir -p .tmp \u0026\u0026 ln -s $PWD/shiba-ota_update-2023121200.zip .tmp/shiba-ota_update-2023121200.zip\n\n# Test only patching\n  export PASSPHRASE_AVB=x PASSPHRASE_OTA=y\nSKIP_CLEANUP=true DEVICE_ID=oriole MAGISK_PREINIT_DEVICE='metadata' bash -c '. rooted-ota.sh \u0026\u0026 createRootedOta'\n\n# Test only releasing\n  GITHUB_TOKEN=gh... \\\n DEBUG=true \\\nGITHUB_REPO=schnatterer/rooted-graphene \\\nOTA_VERSION=2025021100 \\\nRELEASE_ID='' \\\n  bash -c '. rooted-ota.sh \u0026\u0026 releaseOta'\n# Test only GH pages deployment\nGITHUB_REPO=schnatterer/rooted-graphene \\\nDEVICE_ID=oriole \\\nMAGISK_PREINIT_DEVICE=metadata \\\n  bash -c '. rooted-ota.sh \u0026\u0026 findLatestVersion \u0026\u0026 checkBuildNecessary \u0026\u0026 createOtaServerData \u0026\u0026 uploadOtaServerData'\n\n\n# e2e test\n  GITHUB_TOKEN=gh... \\\nGITHUB_REPO=schnatterer/rooted-graphene \\\nDEVICE_ID=oriole \\\nMAGISK_PREINIT_DEVICE=metadata \\\nSKIP_CLEANUP=true \\\nDEBUG=1 \\\n  bash -c '. rooted-ota.sh \u0026\u0026 createAndReleaseRootedOta'\n```\n\n## References, Inspiration\nhttps://github.com/MuratovAS/grapheneos-magisk/blob/main/docker/Dockerfile\n\nhttps://xdaforums.com/t/guide-to-lock-bootloader-while-using-rooted-otaos-magisk-root.4510295/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschnatterer%2Frooted-graphene","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschnatterer%2Frooted-graphene","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschnatterer%2Frooted-graphene/lists"}