tech_surveillance2354 wordsRead on Arc Codex

How GitLab reduced code

Published on: September 22, 2026 14 min read Learn how Flow Registry, a component-based framework that compiles YAML configurations into fully functional LangGraph flows, helped improve scalability and more. 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. Using Flow Registry has reduced our own code-per-agentic-flow by 45%. What is this translating to? All of these benefits are available to customers orchestrating and building agents on GitLab Duo Agent Platform. In this article, we share the architectural principles and lessons from this effort and how to apply them in your environment. 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. 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. 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: We also quickly realized a critical gap that low-level frameworks such as LangGraph do not address: a lack of structure to support consistent development at scale. 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 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. With every flow taking at least 450 lines of ad-hoc Python code and looking like this example, the team's velocity slowed down as engineers struggled to introduce changes, overwhelmed by complexity and coupling. 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. 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. 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. Looking for a way out of that maze, we decided to 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 (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. 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. 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. 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 collaborative, composable, and optimized for AI development efficiency. 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. 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: 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. Components 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: - type: AgentComponent name: "developer_agent" prompt_id: "developer_agent_prompt" inputs: - from: "context:goal" as: "goal" - from: "context:project_id" as: "project_id" toolset: - "read_file" - "find_files" - "edit_file" - "run_command" - "create_merge_request" Under the hood, the 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. flowchart LR %% External input/output input((inputs<br>from<br>shared state)) --&gt; LLMCall End --&gt; output((outputs<br>to shared state)) %% Prompts Prompt["You are expert<br>software<br>engineer ..."] --&gt; LLMCall subgraph Prompts direction TB style Prompts stroke-dasharray: 4 4, stroke:#3CB371 Prompt end %% LLM and internal component LLMCall --&gt; End LLMCall --&gt; RunTools RunTools --&gt; LLMCall subgraph Component direction LR LLMCall[LLM Call] RunTools[Run Tools] End[END] end %% Tools EditFile --&gt; RunTools ReadFile --&gt; RunTools subgraph Tools direction LR style Tools stroke-dasharray: 4 4, stroke:#1E90FF EditFile[Edit file] ReadFile[Read file] end 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. Flow Registry Routers enable agent builders 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. To demonstrate a practical example, let’s take a look at GitLab’s foundational flow: 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. routers: - from: "fix_pipeline_context" condition: input: "context:fix_pipeline_context.final_answer.decision" routes: "add_comment": "fix_pipeline_add_comment" "create_plan": "fix_pipeline_checkout_existing_branch" "direct_code_suggestions": "fix_pipeline_code_suggestions" "no_action": "end" "default_route": "end" 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: 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. The third and final pillar of Flow Registry is a shared state structure that acts as 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 Fix pipeline 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. Flow Registry state structure includes a special catchall attribute called context, which behaves like a nested key-value store (or a JSON object) granting components a versatile storage space. To further complement context attribute flexibility, Flow Registry introduced a dot-notation declarative access to context, a convention familiar from other domains (such as GitLab CI Functions), where access to shared key-value storage must be expressed within static configurations. 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 config for another foundational flow: Code review. # … # Step 5: Fetch lightweight MR metadata (file paths + custom instructions) - name: "fetch_mr_metadata" type: DeterministicStepComponent tool_name: "build_review_merge_request_context" # …. # Step 6: Transform prescan results into structured JSON for review consumption - name: "analyze_prescan_results" type: AgentComponent prompt_id: "analyze_prescan_codebase_results" prompt_version: "^1.0.0" inputs: - from: "context:fetch_mr_metadata.tool_responses" as: "mr_context" - from: "context:prescan_codebase.tool_responses" as: "prescan_tool_responses" optional: True toolset: [] ui_log_events: - "on_agent_final_answer" # ….. routers: # …. - from: "fetch_mr_metadata" to: "analyze_prescan_results" 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 inputs: - from: "context:fetch_mr_metadata.tool_responses" as: "mr_context" 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. 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 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. 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. 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 this one behind GitLab Duo Developer Flow, which is currently operating in production. 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. In addition, the per-flow code cost drops with every new flow added. At the time of writing, 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. 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 GitLab AI Hackathon earlier this year and submitted 600+ agents and flows. 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. 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. 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 custom flows. You can also try GitLab Duo Agent Platform for free. Start your free 30-day GitLab trial No credit card required. Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum. Share your feedbackStart building faster today See what your team can do with the intelligent orchestration platform for DevSecOps.

How it works

Once you click Generate, Ollama reads this article and crafts 5 comprehension questions. Your answers are graded against the article content — general knowledge won't be enough. Score 70+ to count toward your certificate.

Questions are cached — you'll always get the same 5 for this article.