{"id":13638553,"url":"https://github.com/hofstadter-io/cuetils","last_synced_at":"2025-08-23T13:20:21.513Z","repository":{"id":44331256,"uuid":"415030956","full_name":"hofstadter-io/cuetils","owner":"hofstadter-io","description":"CLI and library for diff, patch, and ETL operations on CUE, JSON, and Yaml","archived":false,"fork":false,"pushed_at":"2022-02-23T17:45:58.000Z","size":855,"stargazers_count":78,"open_issues_count":29,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-19T20:16:34.335Z","etag":null,"topics":["configuration","cue","cuelang","diff","etl","golang","jq","json","structural-diff","yaml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hofstadter-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":"hofstadter","open_collective":"hofstadter","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2021-10-08T15:07:15.000Z","updated_at":"2024-04-22T20:39:04.000Z","dependencies_parsed_at":"2022-09-24T19:07:21.617Z","dependency_job_id":null,"html_url":"https://github.com/hofstadter-io/cuetils","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/hofstadter-io/cuetils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hofstadter-io%2Fcuetils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hofstadter-io%2Fcuetils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hofstadter-io%2Fcuetils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hofstadter-io%2Fcuetils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hofstadter-io","download_url":"https://codeload.github.com/hofstadter-io/cuetils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hofstadter-io%2Fcuetils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271749047,"owners_count":24814114,"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","status":"online","status_checked_at":"2025-08-23T02:00:09.327Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["configuration","cue","cuelang","diff","etl","golang","jq","json","structural-diff","yaml"],"created_at":"2024-08-02T01:00:48.481Z","updated_at":"2025-08-23T13:20:21.486Z","avatar_url":"https://github.com/hofstadter-io.png","language":"Go","funding_links":["https://patreon.com/hofstadter","https://opencollective.com/hofstadter"],"categories":["yaml","Projects"],"sub_categories":[],"readme":"# Cuetils\n\nCUE utilities and helpers\nfor working with tree based objects\nin any combination of CUE, Yaml, and JSON.\n\n## Using\n\n### As a command line binary\n\nThe `cuetils` CLI is useful for bulk operations\nor when you don't want to write extra CUE or Go.\n\nDownload a [release from GitHub](https://github.com/hofstadter-io/cuetils/releases).\n\n```\ncuetils -h\n```\n\n### As a Go library\n\nThe Go libraries are optimized and have more capabilities.*\n\n```shell\ngo get github.com/hofstadter-io/cuetils@latest\n```\n\n```\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\n\\* work in progress, unoptimized use the CUE helper and RecurseN\n\n### As a CUE library\n\nThe CUE libraries all use the [RecurseN](#recursen) helper\nand make use of the [\"function\" pattern](https://cuetorials.com/patterns/functions/).\nYou can also write [custom operators](#custom-operators).\n\nAdd to your project with `hof mod` or another method.\nSee: https://cuetorials.com/first-steps/modules-and-packages/#dependency-management\n\n```\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\n\n\n## Structural Helpers\n\n\n- [Count](#count) the nodes in an object\n- [Depth](#depth) how deep an object is\n- [Diff](#diff) two objects, producing a structured diff\n- [Patch](#patch) an object, producing a new object\n- [Pick](#pick) a subojbect from another, selecting only the parts you want\n- [Mask](#mask) a subobject from another, filtering out parts you don't want\n- [Replace](#replace) with a subobject, updating fields found\n- [Upsert](#upsert) with a subobject, updating and adding fields\n- [Transform](#transform) one or more objects into another using CUE\n- [Validate](#validate) one or more objects with the power of CUE\n\n\nThe helpers work by checking if two operands unify.\nWe try to make note of the edge cases where appropriate,\nas it depends on both the operation and the method you are using (CUE, Go, or `cuetils`).\n\n### Count\n\n__#Count__ calculates how many nodes are in an object.\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\na: {\n\tfoo: \"bar\"\n\ta: b: c: \"d\"\n}\ncow: \"moo\"\n```\n\n```shell\n$ cuetils count tree.cue\n9\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\ntree: {\n\ta: {\n\t\tfoo: \"bar\"\n\t\ta: b: c: \"d\"\n\t}\n\tcow: \"moo\"\n}\n\ndepth: (structural.#Count \u0026 { #in: tree }).out\ndepth: 9\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\u003c/details\u003e\n\n\n### Depth\n\n__#Depth__ calculates the deepest branch of an object.\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\na: {\n\tfoo: \"bar\"\n\ta: b: c: \"d\"\n}\ncow: \"moo\"\n```\n\n```shell\n$ cuetils depth tree.cue\n5\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\ntree: {\n\ta: {\n\t\tfoo: \"bar\"\n\t\ta: b: c: \"d\"\n\t}\n\tcow: \"moo\"\n}\n\ndepth: (structural.#Depth \u0026 { #in: tree }).out\ndepth: 5\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n### Diff\n\n__#Diff__ computes a semantic diff object\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t}\n}\n-- b.yaml --\na:\n  c: C\nb: B\n```\n\n```shell\n$ cuetils diff a.json b.yaml\n{\n\t\"+\": {\n\t\tb: \"B\"\n\t}\n\ta: {\n\t\t\"-\": {\n\t\t\tb: \"B\"\n\t\t}\n\t\t\"+\": {\n\t\t\tc: \"C\"\n\t\t}\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\nx: {\n\ta: \"a\"\n\tb: \"b\"\n\td: \"d\"\n\te: {\n\t\ta: \"a\"\n\t\tb: \"b\"\n\t\td: \"d\"\n\t}\n}\n\ny: {\n\tb: \"b\"\n\tc: \"c\"\n\td: \"D\"\n\te:  {\n\t\tb: \"b\"\n\t\tc: \"c\"\n\t\td: 1\n\t}\n}\n\ndiff: (structural.#Diff \u0026 { #X: x, #Y: y }).diff\ndiff: {\n\t\"-\": {\n\t\ta: \"a\"\n\t\td: \"d\"\n\t}\n\te: {\n\t\t\"-\": {\n\t\t\ta: \"a\"\n\t\t\td: \"d\"\n\t\t}\n\t\t\"+\": {\n\t\t\td: 1\n\t\t\tc: \"c\"\n\t\t}\n\t}\n\t\"+\": {\n\t\td: \"D\"\n\t\tc: \"c\"\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\nFor __diff__ and __patch__, `int \u0026 1` like expressions will _not_ be detected.\nLists are not currently supported for __diff__ and __patch__.\nIt may be workable if the list sizes are known and order consistent.\n[Associative Lists](https://cuetorials.com/cueology/futurology/associative-lists/) may solve this issue.\nWe don't currently have good syntax for specifying the key to match elements on.\n\n\n### Patch\n\n__#Patch__ applies a diff object\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- patch.json --\n{\n  \"+\": {\n    b: \"B\"\n  }\n  a: {\n    \"-\": {\n      b: \"B\"\n    }\n    \"+\": {\n      c: \"C\"\n    }\n  }\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t}\n}\n```\n\n```shell\n$ cuetils patch patch.json a.json\n{\n\tb: \"B\"\n\ta: {\n\t\tc: \"C\"\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\nx: {\n\ta: \"a\"\n\tb: \"b\"\n\td: \"d\"\n\te: {\n\t\ta: \"a\"\n\t\tb: \"b\"\n\t\td: \"d\"\n\t}\n}\n\np: {\n\t\"-\": {\n\t\ta: \"a\"\n\t\td: \"d\"\n\t}\n\te: {\n\t\t\"-\": {\n\t\t\ta: \"a\"\n\t\t\td: \"d\"\n\t\t}\n\t\t\"+\": {\n\t\t\td: 1\n\t\t\tc: \"c\"\n\t\t}\n\t}\n\t\"+\": {\n\t\td: \"D\"\n\t\tc: \"c\"\n\t}\n}\n\npatch: (structural.#Patch \u0026 { #X: x, #Y: y }).patch\npatch: {\n\tb: \"b\"\n\tc: \"c\"\n\td: \"D\"\n\te:  {\n\t\tb: \"b\"\n\t\tc: \"c\"\n\t\td: 1\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n### Pick\n\n__#Pick__ extracts a subobject\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- pick.cue --\n{\n\ta: {\n\t\tb: string\n\t}\n\tc: int\n\td: \"D\"\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t},\n\t\"b\": 1,\n\t\"c\": 2,\n\t\"d\": \"D\"\n}\n```\n\n```shell\n$ cuetils pick pick.cue a.json\n{\n\ta: {\n\t\tb: \"B\"\n\t}\n\tc: 2\n\td: \"D\"\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\nx: {\n\ta: \"a\"\n\tb: \"b\"\n\td: \"d\"\n\te: {\n\t\ta: \"a\"\n\t\tb: \"b1\"\n\t\td: \"cd\"\n\t}\n}\np: {\n\tb: string\n\td: int\n\te: {\n\t\ta: _\n\t\tb: =~\"^b\"\n\t\td: =~\"^d\"\n\t}\n}\npick: (structural.#Pick \u0026 { #X: x, #P: p }).pick\npick: {\n\tb: \"b\"\n\te:  {\n\t\ta: \"a\"\n\t\tb: \"b1\"\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n### Mask\n\n__#Mask__ removes a subobject\n\n\u003cdetailsi open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- mask.cue --\n{\n\ta: {\n\t\tb: string\n\t}\n\tc: int\n\td: \"D\"\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t\t\"c\": \"C\"\n\t},\n\t\"b\": 1,\n\t\"c\": 2,\n\t\"d\": \"D\"\n}\n```\n\n```shell\n$ cuetils mask mask.cue a.json\n{\n\ta: {\n\t\tc: \"C\"\n\t}\n\tb: 1\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\nx: {\n\ta: \"a\"\n\tb: \"b\"\n\td: \"d\"\n\te: {\n\t\ta: \"a\"\n\t\tb: \"b1\"\n\t\td: \"cd\"\n\t}\n}\nm: {\n\tb: string\n\td: int\n\te: {\n\t\ta: _\n\t\tb: =~\"^b\"\n\t\td: =~\"^d\"\n\t}\n}\nmask: (structural.#Mask \u0026 { #X: x, #M: m }).mask\nmask: {\n\ta: \"a\"\n\td: \"d\"\n\te:  {\n\t\td: \"cd\"\n\t}\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n### Replace\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- replace.cue --\n{\n\ta: {\n\t\tb: \"b\"\n\t}\n\td: \"d\"\n\te: \"E\"\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t},\n\t\"b\": 1,\n\t\"c\": 2,\n\t\"d\": \"D\"\n}\n```\n\n```shell\n$ cuetils replace replace.cue a.json\n{\n\tb: 1\n\tc: 2\n\ta: {\n\t\tb: \"b\"\n\t}\n\td: \"d\"\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n### Upsert\n\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- upsert.cue --\n{\n\ta: {\n\t\tb: \"b\"\n\t}\n\td: \"d\"\n\te: \"E\"\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t},\n\t\"b\": 1,\n\t\"d\": \"D\"\n}\n```\n\n```shell\n$ cuetils upsert upsert.cue a.json\n{\n\tb: 1\n\ta: {\n\t\tb: \"b\"\n\t}\n\td: \"d\"\n\te: \"E\"\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCUE example\u003c/summary\u003e\n\u003cbr\u003e\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n### Transform\n\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- t.cue --\n#In: _        // required, filled in during processing\n{\n\tB: #In.a.b\n\tC: #In.a.c\n\tD: #In.d\n}\n\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"b\"\n\t\t\"c\": \"c\"\n\t}\n\t\"d\": \"d\"\n}\n```\n\n```shell\n$ cuetils transform t.cue a.json\n{\n\tB: \"b\"\n\tC: \"c\"\n\tD: \"d\"\n}\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n### Validate\n\n\u003cdetails open\u003e\n\u003csummary\u003eCLI example\u003c/summary\u003e\n\u003cbr\u003e\n\n```\n-- schema.cue --\n{\n\ta: {\n\t\tb: int\n\t}\n\tc: int\n\td: \"D\"\n}\n-- a.json --\n{\n\t\"a\": {\n\t\t\"b\": \"B\"\n\t},\n\t\"b\": 1,\n\t\"c\": 2,\n\t\"d\": \"D\"\n}\n```\n\n```shell\n$ cuetils validate schema.cue a.json\na.json\n----------------------\na.b: conflicting values \"B\" and int (mismatched types string and int):\n    ./schema.cue:1:1\n    ./schema.cue:3:6\n    a.json:3:8\n\n\nErrors in 1 file(s)\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eGo example\u003c/summary\u003e\n\u003cbr\u003e\n\n```Go\nimport \"github.com/hofstadter-io/cuetils/structural\"\n```\n\u003c/details\u003e\n\n\n\n### RecurseN\n\nA function factory for bounded recursion, defaulting to 20.\nThis is a pattern to get around CUE's cycle detection\nby creating a struct with fields named for each iteration.\nSee https://cuetorials.com/deep-dives/recursion/ for more details.\n\n```cue\n#RecurseN: {\n\t#maxiter: uint | *20\n\t#funcFactory: {\n\t\t#next: _\n\t\t#func: _\n\t}\n\n\tfor k, v in list.Range(0, #maxiter, 1) {\n\t\t#funcs: \"\\(k)\": (#funcFactory \u0026 {#next: #funcs[\"\\(k+1)\"]}).#func\n\t}\n\t#funcs: \"\\(#maxiter)\": null\n\n\t#funcs[\"0\"]\n}\n```\n\nThe core of the bounded recursion is this structural comprehension (unrolled for loop).\nThe \"recursive call\" is made with the following pattern.\n\n```cue\n(#funcFactory \u0026 {#next: #funcs[\"\\(k+1)\"]}).#func\n```\n\nYou can override the iterations with `{ #maxdepth: 100 }` at the point of\nusage or by creating new helpers from the existing ones.\nYou may need to adjust this\n\n- up for deep objects\n- down if runtime is an issue\n\n```cue\nimport \"github.com/hofstadter-io/cuetils/structural\"\n\n#LeaguesDeep: structural.#Depth \u0026 { #maxdepth: 10000 }\n```\n\n\n### Custom Helpers\n\nYou can make new helpers by building on the `#RecurseN` pattern.\nYou need two definitions, a factory and the user facing, recursed version.\n\n```cue\npackage structural\n\nimport (\n\t\"list\"\n\n\t\"github.com/hofstadter-io/cuetils/recurse\"\n)\n\n// A function factory\n#depthF: {\n\t// always required\n\t#next: _\n\t\n\t// the actual computation, must be named #func\n\t#func: {\n\t\t// you can have any args\n\t\t#in: _\n\t\t// or internal helpers\n\t\t#multi: {...} | [...]\n\t\t\n\t\t// the result, can be named anything\n    depth: {\n\t\t\t// detect leafs\n\t\t\tif (#in \u0026 #multi) == _|_ { 1 }\n\t\t\t// detect struct\n\t\t\tif (#in \u0026 {...}) != _|_ {\n\t\t\t\tlist.Max([for k,v in #in {(#next \u0026 {#in: v}).depth}]) + 1\n\t\t\t}\n\t\t\t// detect list\n\t\t\tif (#in \u0026 [...]) != _|_ {\n\t\t\t\tlist.Max([for k,v in #in {(#next \u0026 {#in: v}).depth}])\n\t\t\t}\n    }\n\t}\n}\n\n// The user facing, recursed version\n#Depth: recurse.#RecurseN \u0026 {#funcFactory: #depthF}\n```\n\nThe core of the recursive calling is:\n\n```cue\n(#next \u0026 {#in: v}).depth\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhofstadter-io%2Fcuetils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhofstadter-io%2Fcuetils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhofstadter-io%2Fcuetils/lists"}