[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DNCPZKKVYZ0VRN8WH3A7VB":3,"skill-same:01M6DNCPZKKVYZ0VRN8WH3A7VB":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":54,"linkOnly":55,"markdownContent":56,"markdownBody":57,"frontMatter":58,"refName":67,"commitSha":68,"skillDirectory":64,"forksCount":69,"repositoryHtmlUrl":70,"repositoryHomepageUrl":6,"ownerHtmlUrl":71,"ownerBlogUrl":72,"ownerDescription":6,"updatedAt":73,"install":74,"resources":87},"01M6DNCPZKKVYZ0VRN8WH3A7VB","orbit-gql-migration",null,"Converts and migrates legacy Orbit JSON DSL queries to Orbit GQL, then checks each converted query read-only against the graph. Legacy queries are objects with query_type, nodes, relationships, or aggregations. Use when a repo, runbook, script, doc, or agent skill contains them. Also use when a `glab orbit query --file` envelope or API body has an object `query`. Also use when a legacy JSON query fails with HTTP 400 compile_error. Do not use for writing new GQL queries (use the orbit skill).","gitlabhq\u002Forbit-knowledge-graph","gitlabhq","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1086321?v=4","01M6DNBRGTY9EE563JBC352AX9","GitLab","01M6DNBRNBHK5TNFR71NE1ZN3M",61,"MIT","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-gql-migration\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53],"orbit gql migration","orbit","gql","migration","Legacy","new","when","dsl","deprecated","error","type","commands","query","objects","do","queries","writing","only","use","read","repo","knowledge","api","knowledge-graph","doc","runbook","file","compile","gitlab","http","2026-11-10 10:12:30",false,"---\nname: orbit-gql-migration\ndescription: Converts and migrates legacy Orbit JSON DSL queries to Orbit GQL, then checks each converted query read-only against the graph. Legacy queries are objects with query_type, nodes, relationships, or aggregations. Use when a repo, runbook, script, doc, or agent skill contains them. Also use when a `glab orbit query --file` envelope or API body has an object `query`. Also use when a legacy JSON query fails with HTTP 400 compile_error. Do not use for writing new GQL queries (use the orbit skill).\nversion: 0.1.0\nlicense: MIT\ncompatibility: Requires glab with the orbit commands and a GitLab instance with Orbit enabled.\nmetadata:\n  audience: developers\n  keywords: orbit, gql, migration, json, dsl, deprecated, glab\n  workflow: ai\n  source-project: gitlab-org\u002Forbit\u002Fknowledge-graph\n  source-path: skills\u002Forbit-gql-migration\n---\n\n# Migrate legacy Orbit JSON queries to GQL\n\nThe Orbit JSON query language is deprecated and removed. Convert each legacy\nquery to GQL (`glab orbit skills get orbit` has the syntax), run it, and keep\nthe GQL. This skill is a temporary migration aid and will be removed. Do not\ncopy it into long-lived tooling. Public API background:\n\u003Chttps:\u002F\u002Fdocs.gitlab.com\u002Fapi\u002Forbit\u002F>.\n\n## Step 0: confirm the instance accepts GQL\n\n```shell\nglab orbit query \"CALL db.schema('Project')\"\n```\n\n- A GQL syntax or compile error means the instance is too old for GQL. Stop and\n  ask the administrator to upgrade GitLab and Orbit. Do not rewrite queries\n  you cannot run.\n- An auth error means the login is missing or expired. Fix it with\n  `glab auth login`, then rerun. An HTTP 403 can instead mean the user has no\n  Orbit access, and logging in again does not fix that. Ask the administrator.\n- A network error or HTTP 429 is not a version problem. Wait and retry.\n\n## Traps\n\n- `neighbors` defaults to `direction: outgoing`. Map the direction you find,\n  and write `->` when it is omitted. `-[...]-` adds the incoming neighbors and\n  returns plausible extra rows.\n- A node alias that is a GQL reserved word fails with \"expected a variable\" at\n  the alias. The check is case-insensitive, so `End` fails too. Rename it. Likely ones: `end`, `desc`, `order`, `in`, `on`, `is`,\n  `as`, `by`, `all`, `any`, `case`, `of`, `set`, `with`, `limit`, `match`.\n  `start` is fine.\n- The query lives in an envelope. Replace the object under `query` with a\n  string of GQL and keep the other envelope fields. Never replace the whole\n  file with bare GQL, because `--file` rejects it. A short query also runs\n  without a file: `glab orbit query '\u003Cgql>'` takes the query text directly.\n- Some constructs have no GQL form. See \"Rejected constructs\".\n\n## Workflow\n\n1. Find legacy queries: `rg -l '\"query_type\"\\s*:'`, `--file` payloads,\n   heredocs, API or MCP call bodies with `nodes` or `relationships`, and skills\n   or prompts that embed them. Skip output files you wrote yourself.\n2. Convert one query at a time with the mapping.\n3. Validate it (below).\n4. Report queries with no equivalent. Leave them for manual rework instead of\n   guessing.\n\n## Validate a conversion\n\nEvery step is read-only.\n\n1. **Run it.** Use raw output so the shape is easy to inspect:\n\n   ```shell\n   glab orbit query --response-format raw \"\u003Cgql>\" > \u002Ftmp\u002Fout.json\n   jq -c '{query_type, row_count, pagination: .result.pagination}' \u002Ftmp\u002Fout.json\n   ```\n\n   Exit 0 means it parsed and ran. HTTP 400 `compile_error` usually names the\n   line and column. Fix it and rerun.\n2. **Compare with what the old query returned.** If you saved old output,\n   compare row count, property names, and the IDs of the first rows. If you\n   did not, use an independent source for the same question, such as the REST\n   API. Five newest merged MRs of a project:\n\n   ```shell\n   glab orbit query --response-format raw \"MATCH (mr:MergeRequest {project_id: \u003Cid>, state: 'merged'}) RETURN mr.iid ORDER BY mr.created_at DESC LIMIT 5\" \\\n     | jq -c '[.result.nodes[] | select(.type==\"MergeRequest\") | .iid]'\n   glab api 'projects\u002F\u003Cid>\u002Fmerge_requests?state=merged&order_by=created_at&sort=desc&per_page=5' | jq -c '[.[].iid]'\n   ```\n\n   For counts, compare each group with the REST `X-Total` header\n   (`glab api -i 'projects\u002F\u003Cid>\u002Fmerge_requests?state=opened&per_page=1'`).\n   Small differences can come from indexing lag; large ones mean the\n   conversion is wrong. The REST API omits `X-Total` above 10,000 rows. On very\n   large projects the counts can also drift by a few percent. Use this check on\n   small and medium projects.\n3. **Check completeness.** `pagination.has_more` true means more rows exist\n   than `LIMIT` returned. That is expected for a capped list. Compare only the\n   rows you asked for.\n4. **Run a control.** Change one filter value to a nonsense value and confirm\n   the row count drops to 0. A query that returns the same rows either way is\n   not filtering.\n5. **Do not trust an empty result.** Probe with a row you know exists\n   (`MATCH (n:Label {id: \u003Cknown id>}) RETURN n LIMIT 1`).\n\n## Mapping\n\n| Legacy JSON construct | GQL |\n| --- | --- |\n| `{\"query\": {...}, ...}` envelope | `{\"query\": \"\u003CGQL text>\", ...}`; keep other fields such as `response_format` |\n| node without `columns` | `RETURN n` (default columns) |\n| `options` (`dynamic_columns`, `include_debug_sql`) | drop it; it never changes semantics. Report `dynamic_columns` use |\n| `id_property` | no known equivalent; report for manual rework |\n| `query_type` | inferred from the pattern; drop it |\n| `nodes[].id` \u002F `entity` | `(id:Entity)`; rename ids that are GQL reserved words, e.g. `end` |\n| `node_ids: [1]` | `{id: 1}` |\n| `node_ids: [1,2,3]` | `WHERE n.id IN [1, 2, 3]` |\n| `id_range {start,end}` | `WHERE n.id >= a AND n.id \u003C= b` |\n| `filters: {p: v}` \u002F `eq` | inline `{p: v}` or `WHERE n.p = v` |\n| `ne: v` | `WHERE n.p \u003C> v` or `NOT n.p = v` |\n| node-level `not: {p: {in: [...]}}` | `WHERE NOT n.p IN [...]` (not postfix `NOT IN`) |\n| `gt\u002Fgte\u002Flt\u002Flte` | `> >= \u003C \u003C=` |\n| `in` | `IN [...]` |\n| `contains\u002Fstarts_with\u002Fends_with` | `CONTAINS \u002F STARTS WITH \u002F ENDS WITH` |\n| `is_null: true` \u002F `false` | `IS NULL` \u002F `IS NOT NULL` |\n| `token_match\u002Fall_tokens\u002Fany_tokens` | same-named functions in `WHERE` |\n| `relationships[{type,from,to}]` | `(from)-[:TYPE]->(to)` |\n| `type: [A,B]` | `-[:A\\|B]->` |\n| `hops: [1,2]` | `-[:TYPE*1..2]->`; max 3 in both |\n| `direction: incoming` | `\u003C-[:T]-` |\n| `direction: both` | `-[:T]-` in a neighbors query only; rejected in a traversal, see below |\n| relationship `filters` (single hop) | `[r:T {p: v}]` or `WHERE r.p = v` |\n| `type: \"*\"` | `-->` |\n| `columns: [a,b]` | `RETURN n.a, n.b` |\n| `columns: \"*\"` | `RETURN properties(n)` |\n| `order_by: \"-n.p\"` | `ORDER BY n.p DESC` (asc: no suffix) |\n| `limit` | `LIMIT n`; default is 30 in both, write it anyway |\n| `aggregations [{count: n, as: x}]` | `RETURN ..., count(n) AS x`; `sum\u002Fmin\u002Fmax\u002Favg` likewise |\n| `group_by: [\"n.p\"]` | the non-aggregate `RETURN` items |\n| `group_by: [\"u\"]` (node) | `RETURN u{.id, .username}` |\n| `group_by [{key, truncate, as}]` | `date_trunc('month', n.p) AS as` |\n| `aggregation_sort: \"-x\"` | `ORDER BY x DESC` |\n| `path_finding` `{from, to, max_depth, rel_types}` | `MATCH path = ANY SHORTEST (a:L {id: 1})-[:T\\|U*1..max_depth]->(b:L {id: 2}) RETURN path`; GQL requires named types, so `rel_types` is mandatory |\n| `neighbors` `{direction, rel_types}` | outgoing (default) `(c:L {id: 1})-[:A\\|B]->(n)`, incoming `\u003C-[:A\\|B]-`, both `-[:A\\|B]-`, then `RETURN c, n`; omitted `rel_types` is `(c)-->(n)` |\n\n## Worked examples\n\nAggregation. Legacy:\n\n```json\n{\"query\": {\"query_type\": \"aggregation\",\n  \"nodes\": [{\"id\": \"mr\", \"entity\": \"MergeRequest\"},\n            {\"id\": \"p\", \"entity\": \"Project\", \"node_ids\": [278964]}],\n  \"relationships\": [{\"type\": \"IN_PROJECT\", \"from\": \"mr\", \"to\": \"p\"}],\n  \"group_by\": [\"mr.state\"],\n  \"aggregations\": [{\"count\": \"mr\", \"as\": \"mrs\"}],\n  \"aggregation_sort\": \"-mrs\", \"limit\": 10}}\n```\n\nGQL:\n\n```gql\nMATCH (mr:MergeRequest)-[:IN_PROJECT]->(p:Project {id: 278964})\nRETURN mr.state, count(mr) AS mrs\nORDER BY mrs DESC\nLIMIT 10\n```\n\nNeighbors with no `direction`, so outgoing. Legacy:\n\n```json\n{\"query\": {\"query_type\": \"neighbors\",\n  \"nodes\": [{\"id\": \"mr\", \"entity\": \"MergeRequest\", \"node_ids\": [482908721]}],\n  \"neighbors\": {\"rel_types\": [\"AUTHORED\", \"IN_PROJECT\"]}, \"limit\": 25}}\n```\n\nGQL:\n\n```gql\nMATCH (mr:MergeRequest {id: 482908721})-[:AUTHORED|IN_PROJECT]->(n)\nRETURN mr, n\nLIMIT 25\n```\n\n## Rejected constructs and workarounds\n\n| Construct | What to do |\n| --- | --- |\n| `OR` between conditions | `IN [...]` for one property; otherwise run two queries |\n| `OPTIONAL MATCH`, `WITH`, `UNION`, `UNWIND` | split into separate queries |\n| `DISTINCT`, `count(*)` | group by the key; `count(node)` |\n| a second `ORDER BY` key | sort the rows client side |\n| no node anchored by an ID or literal filter | anchor one node; `LIMIT` does not count |\n| `direction: both` on a traversal relationship | no equivalent. Run one query per direction, or a neighbors-style query |\n| relationship `filters` on a variable-length hop | no equivalent (GQL rejects it). Any rewrite, such as a chain of filtered single-hop edges, changes the plan and result shape, so check its results by hand |\n| postfix `n.p NOT IN [...]` | `NOT n.p IN [...]` |\n\n## Pitfalls\n\n- Negation exists in both languages: `ne` and the node-level `not` block map\n  to `\u003C>` and `NOT`. Keep semantics identical while migrating; improve after.\n- Compare columns loosely: the legacy order followed node declaration order.\n- Relationship directions follow the schema; the error names the valid one.\n  `CALL db.schema('Node')` lists them.\n- Fan-out on high-cardinality joins: prefer an aggregate.\n- A node alias cannot be reused for a different label.\n- Both languages cap at 16 predicates and 3 hops.\n","# Migrate legacy Orbit JSON queries to GQL\n\nThe Orbit JSON query language is deprecated and removed. Convert each legacy\nquery to GQL (`glab orbit skills get orbit` has the syntax), run it, and keep\nthe GQL. This skill is a temporary migration aid and will be removed. Do not\ncopy it into long-lived tooling. Public API background:\n\u003Chttps:\u002F\u002Fdocs.gitlab.com\u002Fapi\u002Forbit\u002F>.\n\n## Step 0: confirm the instance accepts GQL\n\n```shell\nglab orbit query \"CALL db.schema('Project')\"\n```\n\n- A GQL syntax or compile error means the instance is too old for GQL. Stop and\n  ask the administrator to upgrade GitLab and Orbit. Do not rewrite queries\n  you cannot run.\n- An auth error means the login is missing or expired. Fix it with\n  `glab auth login`, then rerun. An HTTP 403 can instead mean the user has no\n  Orbit access, and logging in again does not fix that. Ask the administrator.\n- A network error or HTTP 429 is not a version problem. Wait and retry.\n\n## Traps\n\n- `neighbors` defaults to `direction: outgoing`. Map the direction you find,\n  and write `->` when it is omitted. `-[...]-` adds the incoming neighbors and\n  returns plausible extra rows.\n- A node alias that is a GQL reserved word fails with \"expected a variable\" at\n  the alias. The check is case-insensitive, so `End` fails too. Rename it. Likely ones: `end`, `desc`, `order`, `in`, `on`, `is`,\n  `as`, `by`, `all`, `any`, `case`, `of`, `set`, `with`, `limit`, `match`.\n  `start` is fine.\n- The query lives in an envelope. Replace the object under `query` with a\n  string of GQL and keep the other envelope fields. Never replace the whole\n  file with bare GQL, because `--file` rejects it. A short query also runs\n  without a file: `glab orbit query '\u003Cgql>'` takes the query text directly.\n- Some constructs have no GQL form. See \"Rejected constructs\".\n\n## Workflow\n\n1. Find legacy queries: `rg -l '\"query_type\"\\s*:'`, `--file` payloads,\n   heredocs, API or MCP call bodies with `nodes` or `relationships`, and skills\n   or prompts that embed them. Skip output files you wrote yourself.\n2. Convert one query at a time with the mapping.\n3. Validate it (below).\n4. Report queries with no equivalent. Leave them for manual rework instead of\n   guessing.\n\n## Validate a conversion\n\nEvery step is read-only.\n\n1. **Run it.** Use raw output so the shape is easy to inspect:\n\n   ```shell\n   glab orbit query --response-format raw \"\u003Cgql>\" > \u002Ftmp\u002Fout.json\n   jq -c '{query_type, row_count, pagination: .result.pagination}' \u002Ftmp\u002Fout.json\n   ```\n\n   Exit 0 means it parsed and ran. HTTP 400 `compile_error` usually names the\n   line and column. Fix it and rerun.\n2. **Compare with what the old query returned.** If you saved old output,\n   compare row count, property names, and the IDs of the first rows. If you\n   did not, use an independent source for the same question, such as the REST\n   API. Five newest merged MRs of a project:\n\n   ```shell\n   glab orbit query --response-format raw \"MATCH (mr:MergeRequest {project_id: \u003Cid>, state: 'merged'}) RETURN mr.iid ORDER BY mr.created_at DESC LIMIT 5\" \\\n     | jq -c '[.result.nodes[] | select(.type==\"MergeRequest\") | .iid]'\n   glab api 'projects\u002F\u003Cid>\u002Fmerge_requests?state=merged&order_by=created_at&sort=desc&per_page=5' | jq -c '[.[].iid]'\n   ```\n\n   For counts, compare each group with the REST `X-Total` header\n   (`glab api -i 'projects\u002F\u003Cid>\u002Fmerge_requests?state=opened&per_page=1'`).\n   Small differences can come from indexing lag; large ones mean the\n   conversion is wrong. The REST API omits `X-Total` above 10,000 rows. On very\n   large projects the counts can also drift by a few percent. Use this check on\n   small and medium projects.\n3. **Check completeness.** `pagination.has_more` true means more rows exist\n   than `LIMIT` returned. That is expected for a capped list. Compare only the\n   rows you asked for.\n4. **Run a control.** Change one filter value to a nonsense value and confirm\n   the row count drops to 0. A query that returns the same rows either way is\n   not filtering.\n5. **Do not trust an empty result.** Probe with a row you know exists\n   (`MATCH (n:Label {id: \u003Cknown id>}) RETURN n LIMIT 1`).\n\n## Mapping\n\n| Legacy JSON construct | GQL |\n| --- | --- |\n| `{\"query\": {...}, ...}` envelope | `{\"query\": \"\u003CGQL text>\", ...}`; keep other fields such as `response_format` |\n| node without `columns` | `RETURN n` (default columns) |\n| `options` (`dynamic_columns`, `include_debug_sql`) | drop it; it never changes semantics. Report `dynamic_columns` use |\n| `id_property` | no known equivalent; report for manual rework |\n| `query_type` | inferred from the pattern; drop it |\n| `nodes[].id` \u002F `entity` | `(id:Entity)`; rename ids that are GQL reserved words, e.g. `end` |\n| `node_ids: [1]` | `{id: 1}` |\n| `node_ids: [1,2,3]` | `WHERE n.id IN [1, 2, 3]` |\n| `id_range {start,end}` | `WHERE n.id >= a AND n.id \u003C= b` |\n| `filters: {p: v}` \u002F `eq` | inline `{p: v}` or `WHERE n.p = v` |\n| `ne: v` | `WHERE n.p \u003C> v` or `NOT n.p = v` |\n| node-level `not: {p: {in: [...]}}` | `WHERE NOT n.p IN [...]` (not postfix `NOT IN`) |\n| `gt\u002Fgte\u002Flt\u002Flte` | `> >= \u003C \u003C=` |\n| `in` | `IN [...]` |\n| `contains\u002Fstarts_with\u002Fends_with` | `CONTAINS \u002F STARTS WITH \u002F ENDS WITH` |\n| `is_null: true` \u002F `false` | `IS NULL` \u002F `IS NOT NULL` |\n| `token_match\u002Fall_tokens\u002Fany_tokens` | same-named functions in `WHERE` |\n| `relationships[{type,from,to}]` | `(from)-[:TYPE]->(to)` |\n| `type: [A,B]` | `-[:A\\|B]->` |\n| `hops: [1,2]` | `-[:TYPE*1..2]->`; max 3 in both |\n| `direction: incoming` | `\u003C-[:T]-` |\n| `direction: both` | `-[:T]-` in a neighbors query only; rejected in a traversal, see below |\n| relationship `filters` (single hop) | `[r:T {p: v}]` or `WHERE r.p = v` |\n| `type: \"*\"` | `-->` |\n| `columns: [a,b]` | `RETURN n.a, n.b` |\n| `columns: \"*\"` | `RETURN properties(n)` |\n| `order_by: \"-n.p\"` | `ORDER BY n.p DESC` (asc: no suffix) |\n| `limit` | `LIMIT n`; default is 30 in both, write it anyway |\n| `aggregations [{count: n, as: x}]` | `RETURN ..., count(n) AS x`; `sum\u002Fmin\u002Fmax\u002Favg` likewise |\n| `group_by: [\"n.p\"]` | the non-aggregate `RETURN` items |\n| `group_by: [\"u\"]` (node) | `RETURN u{.id, .username}` |\n| `group_by [{key, truncate, as}]` | `date_trunc('month', n.p) AS as` |\n| `aggregation_sort: \"-x\"` | `ORDER BY x DESC` |\n| `path_finding` `{from, to, max_depth, rel_types}` | `MATCH path = ANY SHORTEST (a:L {id: 1})-[:T\\|U*1..max_depth]->(b:L {id: 2}) RETURN path`; GQL requires named types, so `rel_types` is mandatory |\n| `neighbors` `{direction, rel_types}` | outgoing (default) `(c:L {id: 1})-[:A\\|B]->(n)`, incoming `\u003C-[:A\\|B]-`, both `-[:A\\|B]-`, then `RETURN c, n`; omitted `rel_types` is `(c)-->(n)` |\n\n## Worked examples\n\nAggregation. Legacy:\n\n```json\n{\"query\": {\"query_type\": \"aggregation\",\n  \"nodes\": [{\"id\": \"mr\", \"entity\": \"MergeRequest\"},\n            {\"id\": \"p\", \"entity\": \"Project\", \"node_ids\": [278964]}],\n  \"relationships\": [{\"type\": \"IN_PROJECT\", \"from\": \"mr\", \"to\": \"p\"}],\n  \"group_by\": [\"mr.state\"],\n  \"aggregations\": [{\"count\": \"mr\", \"as\": \"mrs\"}],\n  \"aggregation_sort\": \"-mrs\", \"limit\": 10}}\n```\n\nGQL:\n\n```gql\nMATCH (mr:MergeRequest)-[:IN_PROJECT]->(p:Project {id: 278964})\nRETURN mr.state, count(mr) AS mrs\nORDER BY mrs DESC\nLIMIT 10\n```\n\nNeighbors with no `direction`, so outgoing. Legacy:\n\n```json\n{\"query\": {\"query_type\": \"neighbors\",\n  \"nodes\": [{\"id\": \"mr\", \"entity\": \"MergeRequest\", \"node_ids\": [482908721]}],\n  \"neighbors\": {\"rel_types\": [\"AUTHORED\", \"IN_PROJECT\"]}, \"limit\": 25}}\n```\n\nGQL:\n\n```gql\nMATCH (mr:MergeRequest {id: 482908721})-[:AUTHORED|IN_PROJECT]->(n)\nRETURN mr, n\nLIMIT 25\n```\n\n## Rejected constructs and workarounds\n\n| Construct | What to do |\n| --- | --- |\n| `OR` between conditions | `IN [...]` for one property; otherwise run two queries |\n| `OPTIONAL MATCH`, `WITH`, `UNION`, `UNWIND` | split into separate queries |\n| `DISTINCT`, `count(*)` | group by the key; `count(node)` |\n| a second `ORDER BY` key | sort the rows client side |\n| no node anchored by an ID or literal filter | anchor one node; `LIMIT` does not count |\n| `direction: both` on a traversal relationship | no equivalent. Run one query per direction, or a neighbors-style query |\n| relationship `filters` on a variable-length hop | no equivalent (GQL rejects it). Any rewrite, such as a chain of filtered single-hop edges, changes the plan and result shape, so check its results by hand |\n| postfix `n.p NOT IN [...]` | `NOT n.p IN [...]` |\n\n## Pitfalls\n\n- Negation exists in both languages: `ne` and the node-level `not` block map\n  to `\u003C>` and `NOT`. Keep semantics identical while migrating; improve after.\n- Compare columns loosely: the legacy order followed node declaration order.\n- Relationship directions follow the schema; the error names the valid one.\n  `CALL db.schema('Node')` lists them.\n- Fan-out on high-cardinality joins: prefer an aggregate.\n- A node alias cannot be reused for a different label.\n- Both languages cap at 16 predicates and 3 hops.\n",{"name":5,"license":15,"version":59,"metadata":60,"description":7,"compatibility":66},"0.1.0",{"audience":61,"keywords":62,"workflow":63,"source-path":64,"source-project":65},"developers","orbit, gql, migration, json, dsl, deprecated, glab","ai","skills\u002Forbit-gql-migration","gitlab-org\u002Forbit\u002Fknowledge-graph","Requires glab with the orbit commands and a GitLab instance with Orbit enabled.","main","4203b926d4648f62373fb7b0b35faf5cbeeb7057",16,"https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph","https:\u002F\u002Fgithub.com\u002Fgitlabhq","https:\u002F\u002Fabout.gitlab.com\u002F","2026-11-12 03:41:13",{"source":8,"skillName":5,"commands":75,"prompt":85,"zipAvailable":86},[76,79,82],{"tool":77,"command":78},"npx","npx skills add gitlabhq\u002Forbit-knowledge-graph --skill orbit-gql-migration",{"tool":80,"command":81},"bunx","bunx skills add gitlabhq\u002Forbit-knowledge-graph --skill orbit-gql-migration",{"tool":83,"command":84},"pnpm","pnpm dlx skills add gitlabhq\u002Forbit-knowledge-graph --skill orbit-gql-migration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-gql-migration\u002FSKILL.md",true,[],[89,108,118,143,160],{"skillNo":90,"name":25,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":54},"01M6DND1MH0WSG6P06WQH7W4T4","Use Orbit (`glab orbit` or `orbit`) to search code and read it with callers and tests. It reads MRs, issues, and failed jobs with the code they cite. Graph queries answer relationship and aggregation questions across GitLab. Skip it for writes that `glab` handles.","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit\u002FSKILL.md",[],[25,95,96,97,98,45,42,99,36,100,101,46,102,39,47,103,104,105,106,107],"search","issues","tests","call","access","code","relationship","across","cli","glab","for","answer","with",{"skillNo":109,"name":110,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":54},"01M6DNCYFSTRBWTR9514M89JCW","orbit-wrapper","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-wrapper\u002FSKILL.md",[],[114,25,115,95,96,97,98,45,42,99,36,100,101,46,102,39,47,103,104,116,105,106,117,107],"orbit wrapper","Wrapper","later","v1",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":54},"01M6DNCV6ZCAE5E3JNCD3736NA","orbit-start","Walk a user through their first GitLab Orbit session. Check the setup, then answer a simple first question and a workflow from the prompt examples with Orbit. Offer to run a prompt again without Orbit, and to show how Orbit works. Use when the user asks to get started with Orbit, try Orbit, or see what Orbit can do.","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-start\u002FSKILL.md",[],[125,126,25,38,127,128,129,45,130,42,99,131,132,133,134,47,135,136,103,104,30,52,137,138,139,140,141,142],"orbit start","start","show","get","session","question","prompt","workflow","check","examples","simple","first","how","run","network","org","graph","orbit cli",{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":149,"publishedAt":54},"01M6WQJSZYKF47WNMSHC3RQSCH","orbit-package-registry","Use Orbit graph queries to answer questions about GitLab Package Registry packages and Container Registry repositories across projects and groups. Use it to find which projects host a package. It covers package versions and their files, declared dependencies, known vulnerabilities, and the pipelines that built them. Load it with the `orbit` skill. Skip it for one project's package list or for publishing, which `glab` and the package manager handle.","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-package-registry\u002FSKILL.md",[],[150,25,151,152,153,154,155,156,45,157,158,99,46,102,159,47,103,52,35,139],"registry","package","orbit package registry","projects","package manager","which","project","files","host","packages",{"skillNo":161,"name":162,"nameZh":6,"description":163,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":164,"categories":165,"keywords":166,"publishedAt":54},"01M6DNCJJ5G29HWE4EACS6ZRB4","orbit-cli","Index and query a local checkout offline with the GitLab Orbit CLI (`orbit`, or `glab orbit`). Reach for it when a question names a symbol or spans code structure. Examples: who calls or extends this, where it is defined, what a file defines, how definitions are distributed. One call replaces many file reads and text greps, including matches in config, templates, and docs. Works on the working tree and unpushed branches, and also searches and reads the project's GitLab. Not a fit: reading one known file, or counts and relationships across GitLab (use the `orbit` skill).","https:\u002F\u002Fgithub.com\u002Fgitlabhq\u002Forbit-knowledge-graph\u002Fblob\u002Fmain\u002Fskills\u002Forbit-cli\u002FSKILL.md",[],[103,25,142,156,167,168,45,130,99,36,100,102,169,170,30,171,172,47,52,137],"local","branches","text","checkout","indexing","structure"]