[{"data":1,"prerenderedAt":1927},["ShallowReactive",2],{"/blog/how-gitlab-reduced-code-per-agentic-flow-ratio":3,"navigation-en-us":1164,"banner-en-us":1595,"footer-en-us":1605,"blog-post-authors-en-us-Mikolaj Wawrzyniak":1865,"blog-related-posts-en-us-how-gitlab-reduced-code-per-agentic-flow-ratio":1881,"blog-share-wrapper-en-us":1907,"next-steps-en-us":1917},{"id":4,"title":5,"authors":6,"body":8,"category":1145,"date":1146,"description":1147,"extension":1148,"externalUrl":1149,"faq":1149,"featured":1150,"heroImage":1151,"meta":1152,"navigation":394,"path":1153,"seo":1154,"slug":1156,"stem":1157,"tags":1158,"template":1162,"updatedDate":1149,"__hash__":1163},"blogPosts/en-us/blog/how-gitlab-reduced-code-per-agentic-flow-ratio.md","How GitLab reduced code-per-agentic-flow ratio by 45%",[7],"Mikolaj Wawrzyniak",{"type":9,"value":10,"toc":1131},"minimark",[11,21,24,53,56,59,64,67,70,73,103,109,116,125,128,131,134,147,150,153,157,163,166,169,187,190,195,200,356,363,560,563,567,577,589,686,689,700,703,707,721,741,754,989,992,1021,1024,1028,1037,1040,1054,1057,1064,1073,1077,1080,1083,1087,1095,1099,1107,1111,1119,1127],[12,13,14,20],"p",{},[15,16,19],"a",{"href":17,"rel":18},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-is-generally-available/",[],"GitLab Duo Agent Platform"," orchestrates and automates complex tasks through agentic flows. A key part of the platform is the Flow Registry, a declarative configuration framework, built from reusable components, that compiles YAML into fully functional LangGraph flows. By using Flow Registry, agent builders — both our GitLab engineers and our customers  can use declarative YAML configurations instead of repetitive, ad-hoc Python implementations. Flow Registry turns bespoke state management and agent wiring duplicated across agents into a set of  reusable components and primitives available to agent builders.",[12,22,23],{},"Using Flow Registry has reduced our own code-per-agentic-flow by 45%. What is this translating to?",[25,26,27,35,41,47],"ul",{},[28,29,30,34],"li",{},[31,32,33],"strong",{},"Faster iteration speed"," due to a declaration framework with reusable components and primitives.",[28,36,37,40],{},[31,38,39],{},"Increased reliability"," because one-off implementation mistakes and boilerplate bugs are handled on a component level.",[28,42,43,46],{},[31,44,45],{},"Lower maintenance cost"," because platform improvements are made once,  but benefit  all agents.",[28,48,49,52],{},[31,50,51],{},"Backward compatibility for our functionalities",", for both our GitLab-authored foundational flows and also customers’ custom flows, because of the abstraction layer.",[12,54,55],{},"All of these benefits are available to customers orchestrating and building agents on GitLab Duo Agent Platform.",[12,57,58],{},"In this article, we share the architectural principles and lessons from this effort and how to apply them in your environment.",[60,61,63],"h2",{"id":62},"langgraph-as-the-foundation-for-gitlab-duo-agent-platform","LangGraph as the foundation for GitLab Duo Agent Platform",[12,65,66],{},"After releasing GitLab Duo Code Suggestions and Duo Chat, we dug into a then-novel technology, autonomous agents. We researched available AI frameworks and selected LangGraph, an agent runtime and low-level orchestration framework from LangChain, as the foundation for GitLab Duo Agent Platform.",[12,68,69],{},"LangGraph's rich feature set, which includes a broad range of model adapters, durable execution, and traceability, combined with an excellent level of engineering autonomy, brought all the necessary building blocks we looked for to start GitLab Duo Agent Platform development.",[12,71,72],{},"During the initial months, GitLab engineers, empowered by LangGraph, swiftly built the foundations of Duo Agent Platform, and before long the team shipped four agentic flows:",[25,74,75,82,89,96],{},[28,76,77],{},[15,78,81],{"href":79,"rel":80},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/software_development/",[],"Software Development Flow",[28,83,84],{},[15,85,88],{"href":86,"rel":87},"https://docs.gitlab.com/user/gitlab_duo_chat/agentic_chat/",[],"Duo Agentic Chat",[28,90,91],{},[15,92,95],{"href":93,"rel":94},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/convert_to_gitlab_ci/",[],"Convert to GitLab CI/CD Flow",[28,97,98],{},[15,99,102],{"href":100,"rel":101},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/developer/",[],"Developer Flow",[12,104,105,106],{},"We also quickly realized a critical gap that low-level frameworks such as LangGraph do not address: ",[31,107,108],{},"a lack of structure to support consistent development at scale.",[12,110,111,112,115],{},"With just four flows present, and a small engineering team working on GitLab Duo Agent Platform at that time, the codebase was growing rapidly. Every flow was implemented as an ad-hoc directed graph, turning into a web of interconnected nodes and edges. The early Duo Agent Platform codebase had ",[31,113,114],{},"no reusability, no composability, and little in the way of shared standards",". It became very difficult to develop new features, and any horizontal platform-wide change seemed like an impossible task.",[12,117,118,119,124],{},"With every flow taking at least 450 lines of ad-hoc Python code and looking like this ",[15,120,123],{"href":121,"rel":122},"https://gitlab.com/gitlab-org/duo-workflow/duo-workflow-service/-/blob/21d695615ee24d232826dd056da23dbf7f4cd4ee/duo_workflow_service/workflow/workflow.py",[],"example",", the team's velocity slowed down as engineers struggled to introduce changes, overwhelmed by complexity and coupling.",[12,126,127],{},"The graph's complexity spilled into the test suite, as well. Each test case depended on an execution propagating through a whole graph, which changed tests from a quality assurance safety net into a boogeyman that nobody wanted to look at.",[12,129,130],{},"It became clear to us that graphs used as an atomic building block at this low abstraction level are not a good match for a platform implementation. To support the scale we envisioned, it was necessary to introduce smaller units, that break down the complexity and reduce cognitive load put on platform engineers maintaining the project.",[12,132,133],{},"Furthermore, graphs with low-level nodes managing model API calls or executing function calls produced by said models, were not the right abstraction for AI engineers either, as they are more accustomed to terms like agents and agent orchestration.",[12,135,136,137,140,141,146],{},"Looking for a way out of that maze, we decided to ",[31,138,139],{},"separate those two concerns — AI engineering from platform development"," — with the introduction of a new layer of abstraction. To do so, we reviewed existing graphs and identified and extracted repeated structures (for example, cycles going between large language model (",[15,142,145],{"href":143,"rel":144},"https://about.gitlab.com/blog/what-is-a-large-language-model-llm/",[],"LLM",") calls and tool execution, implementing agent loops). The refactor brought some relief, as the most complex files had been broken down into smaller pieces that formed the new abstraction layer.",[12,148,149],{},"However, the platform was still far from a scalable state. The extracted graph pieces unfortunately operated with their own state structures, tightly coupled with the flow from which they originated. This prevented us from reusing extracted entities between different flows, and we were concerned that at that point every new flow would be more likely to create its own set of pieces, rather than be composed from ones that already existed. The system was neither collaborative nor efficient, and it was not sustainable in that state for a longer period of time.",[12,151,152],{},"That realization made it apparent — we had to put more effort in, continue to evolve the architecture, and provide clear development guidelines. At that time we already knew that Duo Agent Platform flows wouldn't be exclusively built by other product teams, but that a wider GitLab community would be invited to contribute as well.",[60,154,156],{"id":155},"abstracting-langgraph-details-behind-the-new-flow-registry-framework","Abstracting LangGraph details behind the new Flow Registry framework",[12,158,159,160],{},"Equipped with the past experience, and inspired by ambitious goals, my teammate Alexander Chueshev and I went back to the drawing board, and rethought the system. We set out to introduce a solution that is highly ",[31,161,162],{},"collaborative, composable, and optimized for AI development efficiency.",[12,164,165],{},"We wanted this new iteration to hide low-level LangGraph implementation details, and to stop bothering developers with nodes or edges. The system ought to speak their language — the language of AI engineering — with agents being a central component.",[12,167,168],{},"It was clear to us that AI development reasons in terms of agents, rather than nodes that invoke models, execute tools, etc. Drawing lessons from the past iteration, we decided to base the new framework on three pillars:",[170,171,172,177,182],"ol",{},[28,173,174],{},[31,175,176],{},"Components",[28,178,179],{},[31,180,181],{},"Routers",[28,183,184],{},[31,185,186],{},"Shared state structure",[12,188,189],{},"We were convinced that if we were able to design them well, the new framework would be flexible enough to support any AI flow that users might want to build.",[191,192,194],"h3",{"id":193},"pillar-1-ai-engineering-primitives-as-components","Pillar 1. AI engineering primitives as components",[12,196,197,199],{},[31,198,176],{}," are the central and most important pillar of Flow Registry. They model common primitives such as agents, human-in-the-loop checkpoints, and fixed-logic steps. This pillar lifts the abstraction level to match terminology used within the AI engineering domain. Thanks to components agent builders no longer need to reimplement those primitives from scratch, but can declare them with YAML snippets that look like this example:",[201,202,207],"pre",{"className":203,"code":204,"language":205,"meta":206,"style":206},"language-yaml shiki shiki-themes github-light","     - type: AgentComponent\n        name: \"developer_agent\"\n        prompt_id: \"developer_agent_prompt\"\n        inputs:\n          - from: \"context:goal\"\n            as: \"goal\"\n          - from: \"context:project_id\"\n            as: \"project_id\"\n        toolset:\n          - \"read_file\"\n          - \"find_files\"\n          - \"edit_file\"\n          - \"run_command\"\n          - \"create_merge_request\"\n","yaml","",[208,209,210,230,241,252,261,275,286,298,308,316,324,332,340,348],"code",{"__ignoreMap":206},[211,212,215,219,223,226],"span",{"class":213,"line":214},"line",1,[211,216,218],{"class":217},"sgsFI","     - ",[211,220,222],{"class":221},"shJU0","type",[211,224,225],{"class":217},": ",[211,227,229],{"class":228},"sYBdl","AgentComponent\n",[211,231,233,236,238],{"class":213,"line":232},2,[211,234,235],{"class":221},"        name",[211,237,225],{"class":217},[211,239,240],{"class":228},"\"developer_agent\"\n",[211,242,244,247,249],{"class":213,"line":243},3,[211,245,246],{"class":221},"        prompt_id",[211,248,225],{"class":217},[211,250,251],{"class":228},"\"developer_agent_prompt\"\n",[211,253,255,258],{"class":213,"line":254},4,[211,256,257],{"class":221},"        inputs",[211,259,260],{"class":217},":\n",[211,262,264,267,270,272],{"class":213,"line":263},5,[211,265,266],{"class":217},"          - ",[211,268,269],{"class":221},"from",[211,271,225],{"class":217},[211,273,274],{"class":228},"\"context:goal\"\n",[211,276,278,281,283],{"class":213,"line":277},6,[211,279,280],{"class":221},"            as",[211,282,225],{"class":217},[211,284,285],{"class":228},"\"goal\"\n",[211,287,289,291,293,295],{"class":213,"line":288},7,[211,290,266],{"class":217},[211,292,269],{"class":221},[211,294,225],{"class":217},[211,296,297],{"class":228},"\"context:project_id\"\n",[211,299,301,303,305],{"class":213,"line":300},8,[211,302,280],{"class":221},[211,304,225],{"class":217},[211,306,307],{"class":228},"\"project_id\"\n",[211,309,311,314],{"class":213,"line":310},9,[211,312,313],{"class":221},"        toolset",[211,315,260],{"class":217},[211,317,319,321],{"class":213,"line":318},10,[211,320,266],{"class":217},[211,322,323],{"class":228},"\"read_file\"\n",[211,325,327,329],{"class":213,"line":326},11,[211,328,266],{"class":217},[211,330,331],{"class":228},"\"find_files\"\n",[211,333,335,337],{"class":213,"line":334},12,[211,336,266],{"class":217},[211,338,339],{"class":228},"\"edit_file\"\n",[211,341,343,345],{"class":213,"line":342},13,[211,344,266],{"class":217},[211,346,347],{"class":228},"\"run_command\"\n",[211,349,351,353],{"class":213,"line":350},14,[211,352,266],{"class":217},[211,354,355],{"class":228},"\"create_merge_request\"\n",[12,357,358,359,362],{},"Under the hood, the ",[31,360,361],{},"AgentComponent"," is still a piece of a LangGraph’s graph, whose simplified structure is shown in the diagram below. However, now its implementation complexity is hidden from agent builders, who operate with a more familiar primitive. The same architectural boundaries also benefit framework maintainers, giving them more freedom to modify and extend the underlying implementation, with changes propagating to flows transparently.",[201,364,368],{"className":365,"code":366,"language":367,"meta":206,"style":206},"language-mermaid shiki shiki-themes github-light","flowchart LR\n    %% External input/output\n    input((inputs\u003Cbr>from\u003Cbr>shared state)) --> LLMCall\n    End --> output((outputs\u003Cbr>to shared state))\n\n    %% Prompts\n    Prompt[\"You are expert\u003Cbr>software\u003Cbr>engineer ...\"] --> LLMCall\n    subgraph Prompts\n        direction TB\n        style Prompts stroke-dasharray: 4 4, stroke:#3CB371\n        Prompt\n    end\n\n    %% LLM and internal component\n    LLMCall --> End\n    LLMCall --> RunTools\n    RunTools --> LLMCall\n\n    subgraph Component\n        direction LR\n        LLMCall[LLM Call]\n        RunTools[Run Tools]\n        End[END]\n    end\n\n    %% Tools\n    EditFile --> RunTools\n    ReadFile --> RunTools\n\n    subgraph Tools\n        direction LR\n        style Tools stroke-dasharray: 4 4, stroke:#1E90FF\n        EditFile[Edit file]\n        ReadFile[Read file]\n    end\n","mermaid",[208,369,370,375,380,385,390,396,401,406,411,416,421,426,431,435,440,446,452,458,463,469,475,481,487,493,498,503,509,515,521,526,532,537,543,549,555],{"__ignoreMap":206},[211,371,372],{"class":213,"line":214},[211,373,374],{"class":217},"flowchart LR\n",[211,376,377],{"class":213,"line":232},[211,378,379],{"class":217},"    %% External input/output\n",[211,381,382],{"class":213,"line":243},[211,383,384],{"class":217},"    input((inputs\u003Cbr>from\u003Cbr>shared state)) --> LLMCall\n",[211,386,387],{"class":213,"line":254},[211,388,389],{"class":217},"    End --> output((outputs\u003Cbr>to shared state))\n",[211,391,392],{"class":213,"line":263},[211,393,395],{"emptyLinePlaceholder":394},true,"\n",[211,397,398],{"class":213,"line":277},[211,399,400],{"class":217},"    %% Prompts\n",[211,402,403],{"class":213,"line":288},[211,404,405],{"class":217},"    Prompt[\"You are expert\u003Cbr>software\u003Cbr>engineer ...\"] --> LLMCall\n",[211,407,408],{"class":213,"line":300},[211,409,410],{"class":217},"    subgraph Prompts\n",[211,412,413],{"class":213,"line":310},[211,414,415],{"class":217},"        direction TB\n",[211,417,418],{"class":213,"line":318},[211,419,420],{"class":217},"        style Prompts stroke-dasharray: 4 4, stroke:#3CB371\n",[211,422,423],{"class":213,"line":326},[211,424,425],{"class":217},"        Prompt\n",[211,427,428],{"class":213,"line":334},[211,429,430],{"class":217},"    end\n",[211,432,433],{"class":213,"line":342},[211,434,395],{"emptyLinePlaceholder":394},[211,436,437],{"class":213,"line":350},[211,438,439],{"class":217},"    %% LLM and internal component\n",[211,441,443],{"class":213,"line":442},15,[211,444,445],{"class":217},"    LLMCall --> End\n",[211,447,449],{"class":213,"line":448},16,[211,450,451],{"class":217},"    LLMCall --> RunTools\n",[211,453,455],{"class":213,"line":454},17,[211,456,457],{"class":217},"    RunTools --> LLMCall\n",[211,459,461],{"class":213,"line":460},18,[211,462,395],{"emptyLinePlaceholder":394},[211,464,466],{"class":213,"line":465},19,[211,467,468],{"class":217},"    subgraph Component\n",[211,470,472],{"class":213,"line":471},20,[211,473,474],{"class":217},"        direction LR\n",[211,476,478],{"class":213,"line":477},21,[211,479,480],{"class":217},"        LLMCall[LLM Call]\n",[211,482,484],{"class":213,"line":483},22,[211,485,486],{"class":217},"        RunTools[Run Tools]\n",[211,488,490],{"class":213,"line":489},23,[211,491,492],{"class":217},"        End[END]\n",[211,494,496],{"class":213,"line":495},24,[211,497,430],{"class":217},[211,499,501],{"class":213,"line":500},25,[211,502,395],{"emptyLinePlaceholder":394},[211,504,506],{"class":213,"line":505},26,[211,507,508],{"class":217},"    %% Tools\n",[211,510,512],{"class":213,"line":511},27,[211,513,514],{"class":217},"    EditFile --> RunTools\n",[211,516,518],{"class":213,"line":517},28,[211,519,520],{"class":217},"    ReadFile --> RunTools\n",[211,522,524],{"class":213,"line":523},29,[211,525,395],{"emptyLinePlaceholder":394},[211,527,529],{"class":213,"line":528},30,[211,530,531],{"class":217},"    subgraph Tools\n",[211,533,535],{"class":213,"line":534},31,[211,536,474],{"class":217},[211,538,540],{"class":213,"line":539},32,[211,541,542],{"class":217},"        style Tools stroke-dasharray: 4 4, stroke:#1E90FF\n",[211,544,546],{"class":213,"line":545},33,[211,547,548],{"class":217},"        EditFile[Edit file]\n",[211,550,552],{"class":213,"line":551},34,[211,553,554],{"class":217},"        ReadFile[Read file]\n",[211,556,558],{"class":213,"line":557},35,[211,559,430],{"class":217},[12,561,562],{},"The agent as a component, with the ability to delegate work to subagents, is already a powerful base delivered by Pillar 1 alone. Many contemporary agent platforms consider it a complete and sufficient offering. However, GitLab has larger ambitions for Duo Agent Platform, which Flow Registry realizes with the next two pillars.",[191,564,566],{"id":565},"pillar-2-routers-to-orchestrate-components-into-flows","Pillar 2. Routers to orchestrate components into flows",[12,568,569,570,572,573,576],{},"Flow Registry ",[31,571,181],{}," enable agent builders ",[31,574,575],{},"to orchestrate multiple specialized agents",", or even agentic teams, into a flow to model highly complex business, or software development processes. Even though the largest contemporary models are powerful enough to drive complex assignments on their own, a recent rise in popularity of subagent architecture shows that there are many benefits of assembling multiple agents to collaborate over a single task.",[12,578,579,580,584,585,588],{},"To demonstrate a practical ",[15,581,123],{"href":582,"rel":583},"https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/7ecb96f6c7b2865b0e401eec6f1264900ed49525/duo_workflow_service/agent_platform/v1/flows/configs/fix_pipeline/1.0.0.yml#L371",[],", let’s take a look at GitLab’s foundational flow: ",[31,586,587],{},"Fix pipeline",". This flow is configured with an automated trigger to triage, and fix failing CI pipelines. Because CI pipelines can be very complex, not every failure requires any code change to be resolved, for example sometimes a dependency service might be not responsive, and a plain retry is enough to fix a failure. To acknowledge that dual approach, the flow branches early based on an agent that acts as a judge’s decision. The judge agent's ruling on whether a failure is actionable is then used by Flow Registry Routers to navigate flow execution into the correct branch.",[201,590,592],{"className":203,"code":591,"language":205,"meta":206,"style":206},"routers:\n - from: \"fix_pipeline_context\"\n    condition:\n      input: \"context:fix_pipeline_context.final_answer.decision\"\n      routes:\n        \"add_comment\": \"fix_pipeline_add_comment\"\n        \"create_plan\": \"fix_pipeline_checkout_existing_branch\"\n        \"direct_code_suggestions\": \"fix_pipeline_code_suggestions\"\n        \"no_action\": \"end\"\n        \"default_route\": \"end\"\n",[208,593,594,601,613,620,630,637,647,657,667,677],{"__ignoreMap":206},[211,595,596,599],{"class":213,"line":214},[211,597,598],{"class":221},"routers",[211,600,260],{"class":217},[211,602,603,606,608,610],{"class":213,"line":232},[211,604,605],{"class":217}," - ",[211,607,269],{"class":221},[211,609,225],{"class":217},[211,611,612],{"class":228},"\"fix_pipeline_context\"\n",[211,614,615,618],{"class":213,"line":243},[211,616,617],{"class":221},"    condition",[211,619,260],{"class":217},[211,621,622,625,627],{"class":213,"line":254},[211,623,624],{"class":221},"      input",[211,626,225],{"class":217},[211,628,629],{"class":228},"\"context:fix_pipeline_context.final_answer.decision\"\n",[211,631,632,635],{"class":213,"line":263},[211,633,634],{"class":221},"      routes",[211,636,260],{"class":217},[211,638,639,642,644],{"class":213,"line":277},[211,640,641],{"class":228},"        \"add_comment\"",[211,643,225],{"class":217},[211,645,646],{"class":228},"\"fix_pipeline_add_comment\"\n",[211,648,649,652,654],{"class":213,"line":288},[211,650,651],{"class":228},"        \"create_plan\"",[211,653,225],{"class":217},[211,655,656],{"class":228},"\"fix_pipeline_checkout_existing_branch\"\n",[211,658,659,662,664],{"class":213,"line":300},[211,660,661],{"class":228},"        \"direct_code_suggestions\"",[211,663,225],{"class":217},[211,665,666],{"class":228},"\"fix_pipeline_code_suggestions\"\n",[211,668,669,672,674],{"class":213,"line":310},[211,670,671],{"class":228},"        \"no_action\"",[211,673,225],{"class":217},[211,675,676],{"class":228},"\"end\"\n",[211,678,679,682,684],{"class":213,"line":318},[211,680,681],{"class":228},"        \"default_route\"",[211,683,225],{"class":217},[211,685,676],{"class":228},[12,687,688],{},"It is true that state-of-the-art models should be able to make similar decisions and act on them simultaneously. However, thanks to multi-agent architecture, agent builders can capitalize on the following benefits:",[170,690,691,694,697],{},[28,692,693],{},"Smaller, cheaper models can replace the largest and most expensive ones — a compounding cost advantage for high-frequency automated flows running hundreds of times per day.",[28,695,696],{},"Security posture improves through role separation — read and write capabilities can be split across distinct agents.",[28,698,699],{},"Process guardrails can be enforced when the workflow is known upfront, reducing reliance on model judgment for structured tasks.",[12,701,702],{},"Pillar 2 gives agent builders a choice: Use a simple flow architecture with powerful models, or offload complexity from models prompts into explicit flow structure — catering to a broad range of possible use cases, cost targets, and risk profiles.",[191,704,706],{"id":705},"pillar-3-shared-state-structure","Pillar 3. Shared state structure",[12,708,709,710,713,714,717,718,720],{},"The third and final pillar of Flow Registry is a ",[31,711,712],{},"shared state structure"," that acts as ",[31,715,716],{},"a communication protocol"," between components. Without it, the previous two pillars could not function, because components would lack a reliable way to communicate. Referring back to the ",[31,719,587],{}," example: The judge agent's ruling would be of little value if it could not be reliably forwarded to a Flow Registry Router. More broadly, data produced by one agent is often required by subsequent ones, making a well-defined communication contract essential.",[12,722,723,724,728,729,731,732,734,735,740],{},"Flow Registry state structure includes a special catchall attribute called ",[725,726,727],"em",{},"context",", which behaves like a nested key-value store (or a JSON object) granting components a versatile storage space. To further complement ",[725,730,727],{}," attribute flexibility, Flow Registry introduced a dot-notation declarative access to ",[725,733,727],{},", a convention familiar from other domains (such as ",[15,736,739],{"href":737,"rel":738},"https://docs.gitlab.com/ci/functions/#expression-syntax",[],"GitLab CI Functions","), where access to shared key-value storage must be expressed within static configurations.",[12,742,743,744,749,750,753],{},"To complete the third pillar, convention is required: Flow Registry supports flexible read operations from shared state via said dot-notation, however all writes follow strict rules, providing a set of stable, predictable outputs on which agent builders can rely. To see that in practice, let’s take a look again at a piece of Flow Registry ",[15,745,748],{"href":746,"rel":747},"https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/6276bda602e39c947b09a6549f104327ec91fb78/duo_workflow_service/agent_platform/v1/flows/configs/code_review/1.0.0.yml#L77",[],"config"," for another foundational flow: ",[31,751,752],{},"Code review",".",[201,755,757],{"className":203,"code":756,"language":205,"meta":206,"style":206},"# …\n\n # Step 5: Fetch lightweight MR metadata (file paths + custom instructions)\n  - name: \"fetch_mr_metadata\"\n    type: DeterministicStepComponent\n    tool_name: \"build_review_merge_request_context\"\n\n# ….\n\n  # Step 6: Transform prescan results into structured JSON for review consumption\n  - name: \"analyze_prescan_results\"\n    type: AgentComponent\n    prompt_id: \"analyze_prescan_codebase_results\"\n    prompt_version: \"^1.0.0\"\n    inputs:\n      - from: \"context:fetch_mr_metadata.tool_responses\"\n        as: \"mr_context\"\n      - from: \"context:prescan_codebase.tool_responses\"\n        as: \"prescan_tool_responses\"\n        optional: True\n    toolset: []\n    ui_log_events:\n      - \"on_agent_final_answer\"\n\n# …..\n\nrouters:\n #  ….\n  - from: \"fetch_mr_metadata\"\n    to: \"analyze_prescan_results\"\n",[208,758,759,765,769,774,787,797,807,811,816,820,825,836,844,854,864,871,883,893,904,913,924,932,939,946,950,955,959,965,970,980],{"__ignoreMap":206},[211,760,761],{"class":213,"line":214},[211,762,764],{"class":763},"sAwPA","# …\n",[211,766,767],{"class":213,"line":232},[211,768,395],{"emptyLinePlaceholder":394},[211,770,771],{"class":213,"line":243},[211,772,773],{"class":763}," # Step 5: Fetch lightweight MR metadata (file paths + custom instructions)\n",[211,775,776,779,782,784],{"class":213,"line":254},[211,777,778],{"class":217},"  - ",[211,780,781],{"class":221},"name",[211,783,225],{"class":217},[211,785,786],{"class":228},"\"fetch_mr_metadata\"\n",[211,788,789,792,794],{"class":213,"line":263},[211,790,791],{"class":221},"    type",[211,793,225],{"class":217},[211,795,796],{"class":228},"DeterministicStepComponent\n",[211,798,799,802,804],{"class":213,"line":277},[211,800,801],{"class":221},"    tool_name",[211,803,225],{"class":217},[211,805,806],{"class":228},"\"build_review_merge_request_context\"\n",[211,808,809],{"class":213,"line":288},[211,810,395],{"emptyLinePlaceholder":394},[211,812,813],{"class":213,"line":300},[211,814,815],{"class":763},"# ….\n",[211,817,818],{"class":213,"line":310},[211,819,395],{"emptyLinePlaceholder":394},[211,821,822],{"class":213,"line":318},[211,823,824],{"class":763},"  # Step 6: Transform prescan results into structured JSON for review consumption\n",[211,826,827,829,831,833],{"class":213,"line":326},[211,828,778],{"class":217},[211,830,781],{"class":221},[211,832,225],{"class":217},[211,834,835],{"class":228},"\"analyze_prescan_results\"\n",[211,837,838,840,842],{"class":213,"line":334},[211,839,791],{"class":221},[211,841,225],{"class":217},[211,843,229],{"class":228},[211,845,846,849,851],{"class":213,"line":342},[211,847,848],{"class":221},"    prompt_id",[211,850,225],{"class":217},[211,852,853],{"class":228},"\"analyze_prescan_codebase_results\"\n",[211,855,856,859,861],{"class":213,"line":350},[211,857,858],{"class":221},"    prompt_version",[211,860,225],{"class":217},[211,862,863],{"class":228},"\"^1.0.0\"\n",[211,865,866,869],{"class":213,"line":442},[211,867,868],{"class":221},"    inputs",[211,870,260],{"class":217},[211,872,873,876,878,880],{"class":213,"line":448},[211,874,875],{"class":217},"      - ",[211,877,269],{"class":221},[211,879,225],{"class":217},[211,881,882],{"class":228},"\"context:fetch_mr_metadata.tool_responses\"\n",[211,884,885,888,890],{"class":213,"line":454},[211,886,887],{"class":221},"        as",[211,889,225],{"class":217},[211,891,892],{"class":228},"\"mr_context\"\n",[211,894,895,897,899,901],{"class":213,"line":460},[211,896,875],{"class":217},[211,898,269],{"class":221},[211,900,225],{"class":217},[211,902,903],{"class":228},"\"context:prescan_codebase.tool_responses\"\n",[211,905,906,908,910],{"class":213,"line":465},[211,907,887],{"class":221},[211,909,225],{"class":217},[211,911,912],{"class":228},"\"prescan_tool_responses\"\n",[211,914,915,918,920],{"class":213,"line":471},[211,916,917],{"class":221},"        optional",[211,919,225],{"class":217},[211,921,923],{"class":922},"sYu0t","True\n",[211,925,926,929],{"class":213,"line":477},[211,927,928],{"class":221},"    toolset",[211,930,931],{"class":217},": []\n",[211,933,934,937],{"class":213,"line":483},[211,935,936],{"class":221},"    ui_log_events",[211,938,260],{"class":217},[211,940,941,943],{"class":213,"line":489},[211,942,875],{"class":217},[211,944,945],{"class":228},"\"on_agent_final_answer\"\n",[211,947,948],{"class":213,"line":495},[211,949,395],{"emptyLinePlaceholder":394},[211,951,952],{"class":213,"line":500},[211,953,954],{"class":763},"# …..\n",[211,956,957],{"class":213,"line":505},[211,958,395],{"emptyLinePlaceholder":394},[211,960,961,963],{"class":213,"line":511},[211,962,598],{"class":221},[211,964,260],{"class":217},[211,966,967],{"class":213,"line":517},[211,968,969],{"class":763}," #  ….\n",[211,971,972,974,976,978],{"class":213,"line":523},[211,973,778],{"class":217},[211,975,269],{"class":221},[211,977,225],{"class":217},[211,979,786],{"class":228},[211,981,982,985,987],{"class":213,"line":528},[211,983,984],{"class":221},"    to",[211,986,225],{"class":217},[211,988,835],{"class":228},[12,990,991],{},"Code Review’s agent analyze_prescan_results requires data pulled by a preceding fixed step action fetch_mr_metadata, that dependency is expressed via inputs declared for analyze_prescan_results agent",[201,993,995],{"className":203,"code":994,"language":205,"meta":206,"style":206},"    inputs:\n      - from: \"context:fetch_mr_metadata.tool_responses\"\n        as: \"mr_context\"\n",[208,996,997,1003,1013],{"__ignoreMap":206},[211,998,999,1001],{"class":213,"line":214},[211,1000,868],{"class":221},[211,1002,260],{"class":217},[211,1004,1005,1007,1009,1011],{"class":213,"line":232},[211,1006,875],{"class":217},[211,1008,269],{"class":221},[211,1010,225],{"class":217},[211,1012,882],{"class":228},[211,1014,1015,1017,1019],{"class":213,"line":243},[211,1016,887],{"class":221},[211,1018,225],{"class":217},[211,1020,892],{"class":228},[12,1022,1023],{},"Here, dot-notation and strict output conventions work in tandem, giving agent builders a stable and predictable protocol for moving data between components within a flow.",[60,1025,1027],{"id":1026},"from-python-to-yaml","From Python to YAML",[12,1029,1030,1031,1036],{},"Even though Flow Registry uses declarative YAML configurations, we started the design and rearchitecture in Python, and deferred any declarative configuration API to future iterations. However, once all three Flow Registry pillars ",[15,1032,1035],{"href":1033,"rel":1034},"https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/59706d3de14db9f0d687420ad00d7662343b6eaa/duo_workflow_service/workflows/issue_to_mr/workflow.py",[],"came together"," within a single Python block, it became obvious to us that converting those declarations into a YAML config was just a step away, so we took it.",[12,1038,1039],{},"That change completely decoupled the Flow Registry framework from Python and LangGraph, offering a high-level abstraction syntax for declarative AI flow creation. It established a clean boundary between the platform still implemented on LangGraph foundations, and the external framework's declarative interface, which enabled AI engineers to operate with concepts more familiar to them.",[12,1041,1042,1043,1048,1049,1053],{},"Introduction of Flow Registry framework as a basis for GitLab Duo Agent Platform propelled the whole system from vanilla LangGraph per-use-case implementations into declarative YAML configs like ",[15,1044,1047],{"href":1045,"rel":1046},"https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/77df7f5aa09cdaa0ae421084d2bc6285e7ebbdee/duo_workflow_service/agent_platform/v1/flows/configs/developer/1.0.0.yml#L115",[],"this one"," behind ",[15,1050,1052],{"href":100,"rel":1051},[],"GitLab Duo Developer Flow",", which is currently operating in production.",[12,1055,1056],{},"With the platform decoupled from the framework API designed for AI engineers, the underlying Python codebase becomes shareable across all flows, and any improvements introduced to the engine itself are brought to all flows, further emphasizing the efficiency gains from the clear separation.",[12,1058,1059,1060,1063],{},"In addition, the per-flow code cost drops with every new flow added. At the time of writing, ",[31,1061,1062],{},"the ratio of Python source code per flow has been reduced by 45%"," in favor of Flow Registry — and it will keep improving with every new flow being built.",[12,1065,1066,1067,1072],{},"Finally, AI engineers and domain experts are no longer required to understand any of the underlying platform implementation details, nor do they need to implement any repetitive boilerplate Python code that would require its own test suite and maintenance. This was proven by almost 7,000 developers who signed up for the ",[15,1068,1071],{"href":1069,"rel":1070},"https://about.gitlab.com/blog/gitlab-ai-hackathon-2026-meet-the-winners",[],"GitLab AI Hackathon"," earlier this year and submitted 600+ agents and flows.",[60,1074,1076],{"id":1075},"key-learnings","Key learnings",[12,1078,1079],{},"A key observation we made is that modern AI engineering is still a very young branch of software development, in which common architectural patterns and paradigms haven’t fully been formed yet. However, it does not mean that already established good software engineering practices can’t be applied to AI engineering. In fact, as Flow Registry's story shows, reaching back to existing software engineering paradigms and practices, such as identifying repeated code, extracting it into named entities with clear roles within a system, and forming abstraction layers from them, can yield powerful results.",[12,1081,1082],{},"Beyond that, we would also like to share a few other takeaways that apply broadly to any team building agentic systems, while others are practical starting points for teams working with low-level frameworks like LangGraph.",[191,1084,1086],{"id":1085},"general-principles","General principles",[170,1088,1089,1092],{},[28,1090,1091],{},"Some contemporary agentic frameworks, despite being very powerful, operate at too low a level of abstraction for AI engineering needs, conflating platform concerns with agent development.",[28,1093,1094],{},"Separation of the execution platform from AI engineering enables experts in each domain to operate with more confidence and speed.",[191,1096,1098],{"id":1097},"practical-starting-points-for-low-level-framework-users","Practical starting points for low-level framework users",[170,1100,1101,1104],{},[28,1102,1103],{},"Separation of AI flows from platform implementation can be started by extracting repeated structures from existing AI flows — agentic loops are a good place to start.",[28,1105,1106],{},"A flexible shared data model can be achieved thanks to a key-value-store-like attribute introduced to the model, following patterns established by other orchestration frameworks even outside of the AI domain.",[60,1108,1110],{"id":1109},"try-flow-registry","Try Flow Registry",[12,1112,1113,1114,753],{},"To get a feel for how it all works in practice, visit the AI Catalog where GitLab exposes the resulting Flow Registry orchestration framework for anyone to build ",[15,1115,1118],{"href":1116,"rel":1117},"https://docs.gitlab.com/user/duo_agent_platform/flows/custom/",[],"custom flows",[12,1120,1121,1122,753],{},"You can also ",[15,1123,1126],{"href":1124,"rel":1125},"https://about.gitlab.com/gitlab-duo-agent-platform/",[],"try GitLab Duo Agent Platform for free",[1128,1129,1130],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":206,"searchDepth":232,"depth":232,"links":1132},[1133,1134,1139,1140,1144],{"id":62,"depth":232,"text":63},{"id":155,"depth":232,"text":156,"children":1135},[1136,1137,1138],{"id":193,"depth":243,"text":194},{"id":565,"depth":243,"text":566},{"id":705,"depth":243,"text":706},{"id":1026,"depth":232,"text":1027},{"id":1075,"depth":232,"text":1076,"children":1141},[1142,1143],{"id":1085,"depth":243,"text":1086},{"id":1097,"depth":243,"text":1098},{"id":1109,"depth":232,"text":1110},"engineering","2026-09-22","Learn how Flow Registry, a component-based framework that compiles YAML configurations into fully functional LangGraph flows, helped improve scalability and more.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png",{},"/en-us/blog/how-gitlab-reduced-code-per-agentic-flow-ratio",{"config":1155,"title":5,"description":1147},{"noIndex":1150},"how-gitlab-reduced-code-per-agentic-flow-ratio","en-us/blog/how-gitlab-reduced-code-per-agentic-flow-ratio",[1159,1160,1161],"AI","DevSecOps","features","BlogPost","qmpDkAB49eb41SDMZ6Z1vArrIFnVCUag28hZTUzhLfg",{"logo":1165,"freeTrial":1170,"sales":1175,"login":1180,"items":1185,"search":1516,"minimal":1546,"duo":1565,"switchNav":1574,"pricingDeployment":1585},{"config":1166},{"href":1167,"dataGaName":1168,"dataGaLocation":1169},"/","gitlab logo","header",{"text":1171,"config":1172},"Get free trial",{"href":1173,"dataGaName":1174,"dataGaLocation":1169},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1176,"config":1177},"Request a demo",{"href":1178,"dataGaName":1179,"dataGaLocation":1169},"/request-a-demo/","sales",{"text":1181,"config":1182},"Sign in",{"href":1183,"dataGaName":1184,"dataGaLocation":1169},"https://gitlab.com/users/sign_in/","sign in",[1186,1272,1360,1365,1440,1494],{"text":1187,"left":394,"config":1188,"menu":1190},"Platform",{"dataNavLevelOne":1189},"platform",{"type":1191,"link":1192,"columns":1196,"feature":1261},"lists",{"text":1193,"config":1194},"Explore the Platform",{"href":1195,"dataGaName":1189,"dataGaLocation":1169},"/platform/",[1197,1220,1243],{"title":1198,"items":1199},"Execution & Workflows",[1200,1205,1210,1215],{"text":1201,"config":1202},"CI/CD",{"href":1203,"dataGaLocation":1169,"dataGaName":1204},"/solutions/continuous-integration/","ci/cd",{"text":1206,"config":1207},"Source Code Management",{"href":1208,"dataGaLocation":1169,"dataGaName":1209},"/solutions/source-code-management/","source code management",{"text":1211,"config":1212},"Agile Delivery",{"href":1213,"dataGaLocation":1169,"dataGaName":1214},"/solutions/agile-delivery/","agile delivery",{"text":1216,"config":1217},"Artifact Management",{"href":1218,"dataGaLocation":1169,"dataGaName":1219},"/artifact-central/","artifact management",{"title":1221,"items":1222},"Security & Governance",[1223,1228,1233,1238],{"text":1224,"config":1225},"Application Security Testing",{"href":1226,"dataGaLocation":1169,"dataGaName":1227},"/solutions/application-security-testing/","application security testing",{"text":1229,"config":1230},"Governance & Compliance",{"href":1231,"dataGaLocation":1169,"dataGaName":1232},"/solutions/software-compliance/","governance and compliance",{"text":1234,"config":1235},"Secrets Management",{"href":1236,"dataGaLocation":1169,"dataGaName":1237},"/gitlab-secrets-manager/","secrets management",{"text":1239,"config":1240},"Supply Chain Security",{"href":1241,"dataGaLocation":1169,"dataGaName":1242},"/solutions/supply-chain/","supply chain security",{"title":1244,"items":1245},"Context & AI",[1246,1251,1256],{"text":1247,"config":1248},"Agentic Orchestration",{"href":1249,"dataGaLocation":1169,"dataGaName":1250},"/gitlab-duo-agent-platform/","agentic orchestration",{"text":1252,"config":1253},"Context Graph",{"href":1254,"dataGaLocation":1169,"dataGaName":1255},"/gitlab-orbit/","context graph",{"text":1257,"config":1258},"Visibility & Measurement",{"href":1259,"dataGaLocation":1169,"dataGaName":1260},"/solutions/visibility-measurement/","visibility and measurement",{"config":1262,"title":1265,"text":1266,"link":1267},{"background":1263,"textColor":1264},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1790185102/o7dn32anqcb6z8dgd3as.jpg')","#000","Why GitLab","One platform for speed with control across your software lifecycle.",{"text":1268,"config":1269},"Learn more",{"href":1270,"dataGaName":1271,"dataGaLocation":1169},"/why-gitlab/","why gitlab",{"text":1273,"left":394,"config":1274,"menu":1276},"Solutions",{"dataNavLevelOne":1275},"solutions",{"type":1191,"link":1277,"columns":1281,"feature":1351},{"text":1278,"config":1279},"View all Solutions",{"href":1280,"dataGaName":1275,"dataGaLocation":1169},"/solutions/",[1282,1300,1318],{"title":1283,"items":1284},"Outcomes",[1285,1290,1295],{"text":1286,"config":1287},"DevOps Modernization",{"href":1288,"dataGaLocation":1169,"dataGaName":1289},"/assessments/devops-modernization-assessment/","devops modernization",{"text":1291,"config":1292},"Security Modernization",{"href":1293,"dataGaLocation":1169,"dataGaName":1294},"/assessments/security-modernization-assessment/","security modernization",{"text":1296,"config":1297},"AI Modernization",{"href":1298,"dataGaLocation":1169,"dataGaName":1299},"/assessments/ai-modernization-assessment/","ai modernization",{"title":1301,"items":1302},"By size",[1303,1308,1313],{"text":1304,"config":1305},"Enterprise",{"href":1306,"dataGaLocation":1169,"dataGaName":1307},"/enterprise/","enterprise",{"text":1309,"config":1310},"Small Business",{"href":1311,"dataGaLocation":1169,"dataGaName":1312},"/small-business/","small business",{"text":1314,"config":1315},"Startups",{"href":1316,"dataGaLocation":1169,"dataGaName":1317},"/solutions/startups/","startups",{"title":1319,"items":1320},"Industries",[1321,1326,1331,1336,1341,1346],{"text":1322,"config":1323},"Financial Services",{"href":1324,"dataGaLocation":1169,"dataGaName":1325},"/solutions/finance/","financial services",{"text":1327,"config":1328},"Public Sector",{"href":1329,"dataGaLocation":1169,"dataGaName":1330},"/solutions/public-sector/","public sector",{"text":1332,"config":1333},"Telecommunications",{"href":1334,"dataGaLocation":1169,"dataGaName":1335},"/solutions/telecommunications/","telecommunications",{"text":1337,"config":1338},"Automotive",{"href":1339,"dataGaLocation":1169,"dataGaName":1340},"/solutions/automotive/","automotive",{"text":1342,"config":1343},"Education",{"href":1344,"dataGaLocation":1169,"dataGaName":1345},"/solutions/education/","education",{"text":1347,"config":1348},"Aerospace",{"href":1349,"dataGaLocation":1169,"dataGaName":1350},"/solutions/aerospace/","aerospace",{"config":1352,"title":1353,"text":1354,"link":1355},{"background":1263,"textColor":1264},"GitLab Security Standard","Learn how to harden your software factory and let AI agents earn autonomy, without trading away security.",{"text":1356,"config":1357},"Explore the standard",{"href":1358,"dataGaName":1359,"dataGaLocation":1169},"/gitlab-security-standard/","gitlab security standard",{"text":1361,"config":1362},"Pricing",{"href":1363,"dataGaName":1364,"dataGaLocation":1169,"dataNavLevelOne":1364},"/pricing/","pricing",{"text":1366,"config":1367,"menu":1369},"Resources",{"dataNavLevelOne":1368},"resources",{"type":1191,"link":1370,"columns":1374,"feature":1431},{"text":1371,"config":1372},"View all resources",{"href":1373,"dataGaName":1368,"dataGaLocation":1169},"/resources/",[1375,1403],{"title":1376,"items":1377},"Discover",[1378,1383,1388,1393,1398],{"text":1379,"config":1380},"Docs",{"href":1381,"dataGaName":1382,"dataGaLocation":1169},"https://docs.gitlab.com/","docs",{"text":1384,"config":1385},"University",{"href":1386,"dataGaName":1387,"dataGaLocation":1169},"https://university.gitlab.com/","university",{"text":1389,"config":1390},"Demo Series",{"href":1391,"dataGaName":1392,"dataGaLocation":1169},"/gitlab-technical-demo-series/","demo series",{"text":1394,"config":1395},"Demo Hub",{"href":1396,"dataGaName":1397,"dataGaLocation":1169},"/demo-hub/","demo hub",{"text":1399,"config":1400},"Services",{"href":1401,"dataGaName":1402,"dataGaLocation":1169},"/services/","services",{"title":1404,"items":1405},"Connect",[1406,1411,1416,1421,1426],{"text":1407,"config":1408},"Blog",{"href":1409,"dataGaName":1410,"dataGaLocation":1169},"/blog/","blog",{"text":1412,"config":1413},"Community",{"href":1414,"dataGaName":1415,"dataGaLocation":1169},"/community/","community",{"text":1417,"config":1418},"Customers",{"href":1419,"dataGaName":1420,"dataGaLocation":1169},"/customers/","customers",{"text":1422,"config":1423},"Partners",{"href":1424,"dataGaName":1425,"dataGaLocation":1169},"/partners/","partners",{"text":1427,"config":1428},"Events",{"href":1429,"dataGaName":1430,"dataGaLocation":1169},"/events/","events",{"config":1432,"title":1433,"text":1434,"link":1435},{"background":1263,"textColor":1264},"What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1436,"config":1437},"Read the latest",{"href":1438,"dataGaName":1439,"dataGaLocation":1169},"/whats-new/","whats new",{"text":1441,"config":1442,"menu":1444},"Company",{"dataNavLevelOne":1443},"company",{"type":1191,"columns":1445},[1446],{"items":1447},[1448,1453,1459,1464,1469,1474,1479,1484,1489],{"text":1449,"config":1450},"About",{"href":1451,"dataGaName":1452,"dataGaLocation":1169},"/company/","about",{"text":1454,"config":1455,"footerGa":1458},"Jobs",{"href":1456,"dataGaName":1457,"dataGaLocation":1169},"/jobs/","jobs",{"dataGaName":1457},{"text":1460,"config":1461},"Press",{"href":1462,"dataGaName":1463,"dataGaLocation":1169},"/press/","press",{"text":1465,"config":1466},"Handbook",{"href":1467,"dataGaName":1468,"dataGaLocation":1169},"https://handbook.gitlab.com/","handbook",{"text":1470,"config":1471},"Leadership",{"href":1472,"dataGaName":1473,"dataGaLocation":1169},"/company/team/e-group/","leadership",{"text":1475,"config":1476},"Investor relations",{"href":1477,"dataGaName":1478,"dataGaLocation":1169},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1480,"config":1481},"Trust Center",{"href":1482,"dataGaName":1483,"dataGaLocation":1169},"/security/","trust center",{"text":1485,"config":1486},"AI Transparency Center",{"href":1487,"dataGaName":1488,"dataGaLocation":1169},"/ai-transparency-center/","ai transparency center",{"text":1490,"config":1491},"Newsletter",{"href":1492,"dataGaName":1493,"dataGaLocation":1169},"/company/contact/#contact-forms","newsletter",{"text":1495,"config":1496,"menu":1497},"Contact us",{"dataNavLevelOne":1443},{"type":1191,"columns":1498},[1499],{"items":1500},[1501,1506,1511],{"text":1502,"config":1503},"Talk to sales",{"href":1504,"dataGaName":1505,"dataGaLocation":1169},"/sales/","talk to sales",{"text":1507,"config":1508},"Support portal",{"href":1509,"dataGaName":1510,"dataGaLocation":1169},"https://support.gitlab.com/hc/en-us","support portal",{"text":1512,"config":1513},"Customer portal",{"href":1514,"dataGaName":1515,"dataGaLocation":1169},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1517,"login":1518,"suggestions":1525},"Close",{"text":1519,"link":1520},"To search repositories and projects, login to",{"text":1521,"config":1522},"gitlab.com",{"href":1183,"dataGaName":1523,"dataGaLocation":1524},"search login","search",{"text":1526,"default":1527},"Suggestions",[1528,1530,1533,1535,1539,1543],{"text":19,"config":1529},{"href":1249,"dataGaName":19,"dataGaLocation":1524},{"text":1531,"config":1532},"Code Suggestions (AI)",{"href":1249,"dataGaName":1531,"dataGaLocation":1524},{"text":1201,"config":1534},{"href":1203,"dataGaName":1201,"dataGaLocation":1524},{"text":1536,"config":1537},"GitLab on AWS",{"href":1538,"dataGaName":1536,"dataGaLocation":1524},"/partners/technology-partners/aws/",{"text":1540,"config":1541},"GitLab on Google Cloud",{"href":1542,"dataGaName":1540,"dataGaLocation":1524},"/partners/technology-partners/google-cloud-platform/",{"text":1544,"config":1545},"Why GitLab?",{"href":1270,"dataGaName":1544,"dataGaLocation":1524},{"freeTrial":1547,"mobileIcon":1552,"desktopIcon":1557,"secondaryButton":1560},{"text":1548,"config":1549},"Start free trial",{"href":1550,"dataGaName":1174,"dataGaLocation":1551},"https://gitlab.com/-/trials/new/","nav",{"altText":1553,"config":1554},"Gitlab Icon",{"src":1555,"dataGaName":1556,"dataGaLocation":1551},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1553,"config":1558},{"src":1559,"dataGaName":1556,"dataGaLocation":1551},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1561,"config":1562},"Get Started",{"href":1563,"dataGaName":1564,"dataGaLocation":1551},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1566,"mobileIcon":1570,"desktopIcon":1572},{"text":1567,"config":1568},"Learn more about GitLab Duo",{"href":1249,"dataGaName":1569,"dataGaLocation":1551},"gitlab duo",{"altText":1553,"config":1571},{"src":1555,"dataGaName":1556,"dataGaLocation":1551},{"altText":1553,"config":1573},{"src":1559,"dataGaName":1556,"dataGaLocation":1551},{"button":1575,"mobileIcon":1580,"desktopIcon":1582},{"text":1576,"config":1577},"/switch",{"href":1578,"dataGaName":1579,"dataGaLocation":1551},"#contact","switch",{"altText":1553,"config":1581},{"src":1555,"dataGaName":1556,"dataGaLocation":1551},{"altText":1553,"config":1583},{"src":1584,"dataGaName":1556,"dataGaLocation":1551},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1586,"mobileIcon":1591,"desktopIcon":1593},{"text":1587,"config":1588},"Back to pricing",{"href":1363,"dataGaName":1589,"dataGaLocation":1551,"icon":1590},"back to pricing","GoBack",{"altText":1553,"config":1592},{"src":1555,"dataGaName":1556,"dataGaLocation":1551},{"altText":1553,"config":1594},{"src":1559,"dataGaName":1556,"dataGaLocation":1551},{"title":1596,"button":1597,"config":1603},"Ship at agent speed. Prove every step. Transcend is here.",{"text":1598,"config":1599},"Watch now",{"href":1600,"dataGaName":1601,"dataGaLocation":1602},"/events/transcend/virtual/#watch-gitlab-transcend","transcend-october-2026-banner","global-banner",{"layout":1604,"disabled":1150},"release",{"data":1606},{"text":1607,"source":1608,"edit":1614,"contribute":1619,"config":1624,"items":1629,"minimal":1854},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1609,"config":1610},"View page source",{"href":1611,"dataGaName":1612,"dataGaLocation":1613},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1615,"config":1616},"Edit this page",{"href":1617,"dataGaName":1618,"dataGaLocation":1613},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1620,"config":1621},"Please contribute",{"href":1622,"dataGaName":1623,"dataGaLocation":1613},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1625,"facebook":1626,"youtube":1627,"linkedin":1628},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1630,1677,1734,1781,1822],{"title":1361,"links":1631,"subMenu":1646},[1632,1636,1641],{"text":1633,"config":1634},"View plans",{"href":1363,"dataGaName":1635,"dataGaLocation":1613},"view plans",{"text":1637,"config":1638},"Why Premium?",{"href":1639,"dataGaName":1640,"dataGaLocation":1613},"/pricing/premium/","why premium",{"text":1642,"config":1643},"Why Ultimate?",{"href":1644,"dataGaName":1645,"dataGaLocation":1613},"/pricing/ultimate/","why ultimate",[1647],{"title":1648,"links":1649},"Contact Us",[1650,1653,1655,1657,1662,1667,1672],{"text":1651,"config":1652},"Contact sales",{"href":1504,"dataGaName":1179,"dataGaLocation":1613},{"text":1507,"config":1654},{"href":1509,"dataGaName":1510,"dataGaLocation":1613},{"text":1512,"config":1656},{"href":1514,"dataGaName":1515,"dataGaLocation":1613},{"text":1658,"config":1659},"Status",{"href":1660,"dataGaName":1661,"dataGaLocation":1613},"https://status.gitlab.com/","status",{"text":1663,"config":1664},"Terms of use",{"href":1665,"dataGaName":1666,"dataGaLocation":1613},"/terms/","terms of use",{"text":1668,"config":1669},"Privacy statement",{"href":1670,"dataGaName":1671,"dataGaLocation":1613},"/privacy/","privacy statement",{"text":1673,"config":1674},"Cookie preferences",{"dataGaName":1675,"dataGaLocation":1613,"id":1676,"isOneTrustButton":394},"cookie preferences","ot-sdk-btn",{"title":1187,"links":1678,"subMenu":1692},[1679,1682,1684,1686,1688,1690],{"text":1680,"config":1681},"Explore the platform",{"href":1195,"dataGaName":1189,"dataGaLocation":1613},{"text":1247,"config":1683},{"href":1249,"dataGaName":1250,"dataGaLocation":1613},{"text":1201,"config":1685},{"href":1203,"dataGaName":1204,"dataGaLocation":1613},{"text":1252,"config":1687},{"href":1254,"dataGaName":1255,"dataGaLocation":1613},{"text":1234,"config":1689},{"href":1236,"dataGaName":1237,"dataGaLocation":1613},{"text":1265,"config":1691},{"href":1270,"dataGaName":1271,"dataGaLocation":1613},[1693],{"title":1694,"links":1695},"Topics",[1696,1700,1705,1710,1715,1719,1724,1729],{"text":1201,"config":1697},{"href":1698,"dataGaName":1699,"dataGaLocation":1613},"/topics/ci-cd/","cicd",{"text":1701,"config":1702},"GitOps",{"href":1703,"dataGaName":1704,"dataGaLocation":1613},"/topics/gitops/","gitops",{"text":1706,"config":1707},"DevOps",{"href":1708,"dataGaName":1709,"dataGaLocation":1613},"/topics/devops/","devops",{"text":1711,"config":1712},"Version Control",{"href":1713,"dataGaName":1714,"dataGaLocation":1613},"/topics/version-control/","version control",{"text":1160,"config":1716},{"href":1717,"dataGaName":1718,"dataGaLocation":1613},"/topics/devsecops/","devsecops",{"text":1720,"config":1721},"Cloud Native",{"href":1722,"dataGaName":1723,"dataGaLocation":1613},"/topics/cloud-native/","cloud native",{"text":1725,"config":1726},"AI for Coding",{"href":1727,"dataGaName":1728,"dataGaLocation":1613},"/topics/devops/ai-for-coding/","ai for coding",{"text":1730,"config":1731},"Agentic AI",{"href":1732,"dataGaName":1733,"dataGaLocation":1613},"/topics/agentic-ai/","agentic ai",{"title":1273,"links":1735},[1736,1739,1742,1745,1748,1751,1753,1755,1757,1759,1761,1764,1766,1769,1773,1777],{"text":1737,"config":1738},"DevOps modernization",{"href":1288,"dataGaName":1289,"dataGaLocation":1613},{"text":1740,"config":1741},"Security modernization",{"href":1293,"dataGaName":1294,"dataGaLocation":1613},{"text":1743,"config":1744},"AI modernization",{"href":1298,"dataGaName":1299,"dataGaLocation":1613},{"text":1746,"config":1747},"Financial services",{"href":1324,"dataGaName":1325,"dataGaLocation":1613},{"text":1749,"config":1750},"Public sector",{"href":1329,"dataGaName":1330,"dataGaLocation":1613},{"text":1332,"config":1752},{"href":1334,"dataGaName":1335,"dataGaLocation":1613},{"text":1337,"config":1754},{"href":1339,"dataGaName":1340,"dataGaLocation":1613},{"text":1342,"config":1756},{"href":1344,"dataGaName":1345,"dataGaLocation":1613},{"text":1347,"config":1758},{"href":1349,"dataGaName":1350,"dataGaLocation":1613},{"text":1304,"config":1760},{"href":1306,"dataGaName":1307,"dataGaLocation":1613},{"text":1762,"config":1763},"Small business",{"href":1311,"dataGaName":1312,"dataGaLocation":1613},{"text":1314,"config":1765},{"href":1316,"dataGaName":1317,"dataGaLocation":1613},{"text":1701,"config":1767},{"href":1768,"dataGaName":1704,"dataGaLocation":1613},"/solutions/gitops/",{"text":1770,"config":1771},"Software composition analysis",{"href":1241,"dataGaName":1772,"dataGaLocation":1613},"software composition analysis",{"text":1774,"config":1775},"Value stream management",{"href":1259,"dataGaName":1776,"dataGaLocation":1613},"value stream management",{"text":1778,"config":1779},"All solutions",{"href":1280,"dataGaName":1780,"dataGaLocation":1613},"all solutions",{"title":1366,"links":1782},[1783,1788,1793,1795,1797,1799,1801,1803,1805,1807,1809,1811,1813,1815,1818],{"text":1784,"config":1785},"Install",{"href":1786,"dataGaName":1787,"dataGaLocation":1613},"/install/","install",{"text":1789,"config":1790},"Quick start guides",{"href":1791,"dataGaName":1792,"dataGaLocation":1613},"/get-started/","quick setup checklists",{"text":1379,"config":1794},{"href":1381,"dataGaName":1382,"dataGaLocation":1613},{"text":1384,"config":1796},{"href":1386,"dataGaName":1387,"dataGaLocation":1613},{"text":1389,"config":1798},{"href":1391,"dataGaName":1392,"dataGaLocation":1613},{"text":1394,"config":1800},{"href":1396,"dataGaName":1397,"dataGaLocation":1613},{"text":1399,"config":1802},{"href":1401,"dataGaName":1402,"dataGaLocation":1613},{"text":1407,"config":1804},{"href":1409,"dataGaName":1410,"dataGaLocation":1613},{"text":1412,"config":1806},{"href":1414,"dataGaName":1415,"dataGaLocation":1613},{"text":1417,"config":1808},{"href":1419,"dataGaName":1420,"dataGaLocation":1613},{"text":1422,"config":1810},{"href":1424,"dataGaName":1425,"dataGaLocation":1613},{"text":1427,"config":1812},{"href":1429,"dataGaName":1430,"dataGaLocation":1613},{"text":1490,"config":1814},{"href":1492,"dataGaName":1493,"dataGaLocation":1613},{"text":1816,"config":1817},"What's new",{"href":1438,"dataGaName":1439,"dataGaLocation":1613},{"text":1819,"config":1820},"All resources",{"href":1373,"dataGaName":1821,"dataGaLocation":1613},"all resources",{"title":1441,"links":1823},[1824,1826,1828,1830,1832,1834,1836,1838,1840,1844,1849],{"text":1449,"config":1825},{"href":1451,"dataGaName":1443,"dataGaLocation":1613},{"text":1454,"config":1827},{"href":1456,"dataGaName":1457,"dataGaLocation":1613},{"text":1460,"config":1829},{"href":1462,"dataGaName":1463,"dataGaLocation":1613},{"text":1465,"config":1831},{"href":1467,"dataGaName":1468,"dataGaLocation":1613},{"text":1470,"config":1833},{"href":1472,"dataGaName":1473,"dataGaLocation":1613},{"text":1475,"config":1835},{"href":1477,"dataGaName":1478,"dataGaLocation":1613},{"text":1480,"config":1837},{"href":1482,"dataGaName":1483,"dataGaLocation":1613},{"text":1485,"config":1839},{"href":1487,"dataGaName":1488,"dataGaLocation":1613},{"text":1841,"config":1842},"Sustainability",{"href":1843,"dataGaName":1841,"dataGaLocation":1613},"/sustainability/",{"text":1845,"config":1846},"Diversity, inclusion and belonging (DIB)",{"href":1847,"dataGaName":1848,"dataGaLocation":1613},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1850,"config":1851},"Modern Slavery Transparency Statement",{"href":1852,"dataGaName":1853,"dataGaLocation":1613},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1855},[1856,1859,1862],{"text":1857,"config":1858},"Terms",{"href":1665,"dataGaName":1666,"dataGaLocation":1613},{"text":1860,"config":1861},"Cookies",{"dataGaName":1675,"dataGaLocation":1613,"id":1676,"isOneTrustButton":394},{"text":1863,"config":1864},"Privacy",{"href":1670,"dataGaName":1671,"dataGaLocation":1613},[1866],{"id":1867,"title":7,"body":1149,"config":1868,"content":1870,"description":1149,"extension":1875,"meta":1876,"navigation":394,"path":1877,"seo":1878,"stem":1879,"__hash__":1880},"blogAuthors/en-us/blog/authors/mikolaj-wawrzyniak.yml",{"template":1869},"BlogAuthor",{"name":7,"config":1871},{"headshot":1872,"socialProof":1873},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1783429341/c9wg6qivdwt4zyirhzdg.png",{"gitlabHandle":1874},"mikolaj_wawrzyniak","yml",{},"/en-us/blog/authors/mikolaj-wawrzyniak",{},"en-us/blog/authors/mikolaj-wawrzyniak","qkE5HNDno9DueXh4uE9olnptvYtZ2L2mxuQu-yr3-po",[1882,1890,1898],{"title":1883,"description":1884,"heroImage":1885,"category":1145,"date":1886,"authors":1887,"slug":1889,"externalUrl":1149},"Two front doors: Module-level access in a Django GRC app","A technical deep-dive on restructuring a Django internal tool to support two distinct GitLab teams: Security Compliance and Internal Audit.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097663/Blog/Hero%20Images/Blog/Hero%20Images/Workflow%201800x945_2gQoQIbY9NvjLFpXtsxtXy_1750097663612.png","2026-10-05",[1888],"Donovan Felton","module-level-access-in-a-django-grc-app",{"title":1891,"description":1892,"heroImage":1893,"category":1145,"date":1894,"authors":1895,"slug":1897,"externalUrl":1149},"Co-Create: Building GitLab with our users","How GitLab users collaborated with us to build practical product improvements in the first half of 2026.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099203/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2820%29_2bJGC5ZP3WheoqzlLT05C5_1750099203484.png","2026-09-10",[1896],"Isa Huerga","co-create-h1-2026",{"title":1899,"description":1900,"heroImage":1901,"category":1145,"date":1902,"authors":1903,"slug":1906,"externalUrl":1149},"Git was built for humans — agents need an upgrade","See how GitLab's next-gen SCM scales concurrency for agents, and why a new backend must address provenance and lifecycle challenges.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773856365/gsx2c0vqlswox3ldmq88.jpg","2026-08-26",[1904,1905],"Kranthi Erusu","Jessica Taylor","gitlab-next-gen-scm",{"header":1908,"text":1909,"button":1913,"disclaimer":1916},"Start your free\n\n30-day GitLab trial\n",[1910,1911,1912],"GitLab Duo Agent Platform access","Try our most advanced features","Automate complex tasks with AI",{"text":1171,"config":1914},{"href":1915,"dataGaName":1174,"dataGaLocation":1410},"https://gitlab.com/-/trials/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/blog/","No credit card required.",{"header":1918,"blurb":1919,"button":1920,"secondaryButton":1925},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1921,"config":1922},"Get your free trial",{"href":1923,"dataGaName":1174,"dataGaLocation":1924},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1651,"config":1926},{"href":1504,"dataGaName":1179,"dataGaLocation":1924},1791944922474]