[{"data":1,"prerenderedAt":803},["ShallowReactive",2],{"/en-us/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions":3,"navigation-en-us":43,"banner-en-us":453,"footer-en-us":463,"blog-post-authors-en-us-Fatima Sarah Khalid":702,"blog-related-posts-en-us-building-a-text-adventure-using-cplusplus-and-code-suggestions":716,"assessment-promotions-en-us":756,"next-steps-en-us":793},{"id":4,"title":5,"authorSlugs":6,"body":8,"categorySlug":9,"config":10,"content":14,"description":8,"extension":28,"isFeatured":12,"meta":29,"navigation":30,"path":31,"publishedDate":20,"seo":32,"stem":37,"tagSlugs":38,"__hash__":42},"blogPosts/en-us/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions.yml","Building A Text Adventure Using Cplusplus And Code Suggestions",[7],"fatima-sarah-khalid",null,"ai-ml",{"slug":11,"featured":12,"template":13},"building-a-text-adventure-using-cplusplus-and-code-suggestions",false,"BlogPost",{"title":15,"description":16,"authors":17,"heroImage":19,"date":20,"body":21,"category":9,"tags":22},"Explore the Dragon Realm: Build a C++ adventure game with a little help from AI","How to use GitLab Duo Code Suggestions to create a text-based adventure game, including magical locations to visit and items to procure, using C++.",[18],"Fatima Sarah Khalid","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663344/Blog/Hero%20Images/compassinfield.jpg","2023-08-24","Learning, for me, has never been about reading a textbook or sitting in on a lecture - it's been about experiencing and immersing myself in a hands-on challenge. This is particulary true for new programming languages. With [GitLab Duo Code Suggestions](https://about.gitlab.com/gitlab-duo-agent-platform/), artificial intelligence (AI) becomes my interactive guide, providing an environment for trial, error, and growth. In this tutorial, we will build a text-based adventure game in C++ by using Code Suggestions to learn the programming language along the way.\n\nYou can use this table of contents to navigate into each section. It is recommended to read top-down for the best learning experience.\n\n- [Setup](#setup)\n  - [Installing VS Code](#installing-vs-code)\n  - [Installing Clang as a compiler](#installing-clang-as-a-compiler)\n  - [Setting up VS Code](#setting-up-vs-code)\n- [Getting started](#getting-started)\n  - [Compiling and running your program](#compiling-and-running-your-program)\n- [Setting the text adventure stage](#setting-the-adventure-stage)\n- [Defining the adventure: Variables](#defining-the-adventure-variables)\n- [Crafting the adventure: Making decisions with conditionals](#crafting-the-adventure-making-decisions-with-conditionals)\n- [Structuring the narrative: Characters](#structuring-the-narrative-characters)\n- [Structuring the narrative: Items](#structuring-the-narrative-items)\n- [Applying what we've learned at the Grand Library](#applying-what-weve-learned-at-the-grand-library)\n- [See you next time in the Dragon Realm](#see-you-next-time-in-the-dragon-realm)\n- [Share your feedback](#share-your-feedback)\n\n> Download [GitLab Ultimate for free](https://about.gitlab.com/gitlab-duo-agent-platform/) for a trial of GitLab Duo Code Suggestions.\n\n## Setup\nYou can follow this tutorial in your [preferred and supported IDE](https://docs.gitlab.com/ee/user/project/repository/code_suggestions.html#enable-code-suggestions-in-other-ides-and-editors). Review the documentation to enable Code Suggestions for [GitLab.com SaaS](https://docs.gitlab.com/ee/user/project/repository/code_suggestions.html#enable-code-suggestions-on-gitlab-saas) or [GitLab self-managed instances](https://docs.gitlab.com/ee/user/project/repository/code_suggestions.html#enable-code-suggestions-on-self-managed-gitlab).\n\nThese installation instructions are for macOS Ventura on M1 Silicon.\n\n### Installing VS Code\n\n* Download and install [VS Code](https://code.visualstudio.com/download).\n* Alternatively, you can also install it as a Homebrew cask: `brew install --cask visual-studio-code`.\n\n### Installing Clang as a compiler\n\n* On macOS, you'll need to install some developer tools. Open your terminal and type:\n\n```text\nxcode-select --install\n```\n\nThis will prompt you to install Xcode's command line tools, which include the [Clang C++ compiler](https://clang.llvm.org/get_started.html).\n\nAfter the installation, you can check if `clang++` is installed by typing:\n\n```text\nclang++ --version\n```\n\nYou should see an output that includes some information about the Clang version you have installed.\n\n### Setting up VS Code\n\n* Launch VS Code.\n* Install and configure [the GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).\n* Optionally, in VS Code, install the [C/C++ Intellisense extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), which helps with debugging C/C++.\n\n## Getting started\nNow, let's start building this magical adventure with C++. We'll start with a \"Hello World\" example.\n\nCreate a new project `learn-ai-cpp-adventure`. In the project root, create `adventure.cpp`. The first part of every C++ program is the `main()` function. It's the entry point of the program.\n\nWhen you start writing `int main() {`, Code Suggestions will help autocomplete the function with some default parameters.\n\n![adventure.cpp with a hello world implementation suggested by Code Suggestions](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/0-helloworld.png){: .shadow}\n\n```cpp\nint main()\n{\n    cout \u003C\u003C \"Hello World\" \u003C\u003C endl;\n    return 0;\n}\n```\n\nWhile this is a good place to start, we need to add an include and update the output statement:\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Main function, the starting point of the program\nint main()\n{\n    // Print \"Hello World!\" to the console\n    std::cout \u003C\u003C \"Hello World!\" \u003C\u003C std::endl;\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\nThe program prints \"Hello World!\" to the console when executed.\n\n* `#include \u003Ciostream>`: Because we are building a text-based adventure, we will rely on input from the player using input and output operations (I/O) in C++. This include is a preprocessor directive that tells our program to include the `iostream` library, which provides facilities to use input and output streams, such as `std::cout` for output.\n\n* You might find that Code Suggestions suggests `int main(int argc, char* argv[])` as the definition of our main function. The parameters `(int argc, char* argv[])` are used to pass command-line arguments to the program. Code Suggestions added them as default parameters, but they are not needed if you're not using command-line arguments. In that case, we can also define the main function as `int main()`.\n\n* `std::cout \u003C\u003C \"Hello World!\" \u003C\u003C std::endl;`: outputs \"Hello World\" to the console. The stream operator `\u003C\u003C` is used to send the string to output. `std::endl` is an end-line character.\n\n* `return 0;`: we use `return 0;` to indicate the end of the `main()` function and return a value of 0. In C++, it is good practice to return 0 to indicate the program has completed successfully.\n\n### Compiling and running your program\nNow that we have some code, let's review how we'll compile and run this program.\n* Open your terminal or use the terminal in VSCode (View -> Terminal).\n* Navigate to your project directory.\n* Compile your program by typing:\n\n```bash\nclang++ adventure.cpp -o adventure\n```\n\nThis command tells the Clang++ compiler to compile adventure.cpp and create an executable named adventure. After this, run your program by typing:\n\n```shell\n./adventure\n```\n\nYou should see \"Hello World!\" printed in the terminal.\n\nBecause our tutorial uses a single source file `adventure.cpp`, we can use the compiler directly to build our program. In the future, if the program grows beyond a file, we'll set up additional configurations to handle compilation.\n\n## Setting the text adventure stage\nBefore we get into more code, let's set the stage for our text adventure.\n\nFor this text adventure, players will explore the Dragon Realm. The Dragon Realm is full of mountains, lakes, and magic. Our player will enter the Dragon Realm for the first time, explore different locations, meet new characters, collect magical items, and journal their adventure. At every location, they will be offered choices to decide the course of their journey.\n\nTo kick off our adventure into the Dragon Realm, let's update our `adventure.cpp main()` function to be more specific. As you update the welcome message, you might find that Code Suggestions already knows we're building a game.\n\n![adventure.cpp - Code Suggestions offers suggestion of welcoming users to the Dragon Realm and knows its a game](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/1-welcome-to-the-realm.png){: .shadow}\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Main function, the starting point of the program\nint main()\n{\n    // Print \"Hello World!\" to the console\n    std::cout \u003C\u003C \"Welcome to the Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\n## Defining the adventure: Variables\nA variable stores data that can be used throughout the program scope in the `main()` function. A variable is defined by a type, which indicates the kind of data it can hold.\n\nLet's create a variable to hold our player's name and give it the type `string`. A `string` is designed to hold a sequence of characters so it's perfect for storing our player's name.\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Main function, the starting point of the program\nint main()\n{\n    // Print \"Hello World!\" to the console\n    std::cout \u003C\u003C \"Welcome to the Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Declare a string variable to hold the player's name\n    std::string playerName;\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\nAs you do this, you may notice that Code Suggestions knows what's coming next - prompting the user for their player's name.\n\n![adventure.cpp - Code Suggestions suggests welcoming the player with the playerName variable](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/2-player-name-variable.png){: .shadow}\n\nWe may be able to get more complete and specific Code Suggestions by providing comments about what we'd like to do with the name - personally welcome the player to the game. Start by adding our plan of action in comments.\n\n```cpp\n\n    // Declare a string variable to hold the player's name\n    std::string playerName;\n\n    // Prompt the user to enter their player name\n\n    // Display a personalized welcome message to the player with their name\n\n```\n\nTo capture the player's name from input, we need to use the `std::cin` object from the `iostream` library to fetch input from the player using the extraction operator `>>`. If you start typing `std::` to start prompting the user, Code Suggestions will make some suggestions to help you gather user input and save it to our `playerName` variable.\n\n![adventure.cpp - Code Suggestions prompts the user to input their player name](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/2.1-player-name-input.png){: .shadow}\n\nNext, to welcome our player personally to the game, we want to use `std::cout` and the `playerName` variable together:\n\n```cpp\n\n    // Declare a string variable to store the player name\n    std::string playerName;\n\n    // Prompt the user to enter their player name\n    std::cout \u003C\u003C \"Please enter your name: \";\n    std::cin >> playerName;\n\n    // Display a personalized welcome message to the player with their name\n    std::cout \u003C\u003C \"Welcome \" \u003C\u003C playerName \u003C\u003C \" to The Dragon Realm!\" \u003C\u003C std::endl;\n\n```\n\n## Crafting the adventure: Making decisions with conditionals\nIt's time to introduce our player to the different locations in tbe Dragon Realm they can visit. To prompt our player with choices, we use conditionals. Conditionals allow programs to take different actions based on criteria, such as user input.\n\nLet's offer the player a selection of locations to visit and capture their choice as an `int` value that corresponds to the location they picked.\n\n```cpp\n// Display a personalized welcome message to the player with their name\nstd::cout \u003C\u003C \"Welcome \" \u003C\u003C playerName \u003C\u003C \" to The Dragon Realm!\" \u003C\u003C std::endl;\n\n// Declare an int variable to capture the user's choice\nint choice;\n```\n\nThen, we want to offer the player the different locations that are possible for that choice. Let's start with a comment and prompt Code Suggestions with `std::cout` to fill out the details for us.\n\n![adventure.cpp - Code Suggestions suggests a multiline output for all the locations listed in the code below](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3-setup-location-choice.png){: .shadow}\n\nAs you accept the suggestions, Code Suggestions will help build out the output and ask the player for their input.\n\n![adventure.cpp - Code Suggestions suggests a multiline output for all the locations listed in the code below and asks for player input](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.1-capture-player-location-choice.png){: .shadow}\n\n```cpp\n\n    // Declare an int variable to capture the user's choice\n    int choice;\n\n    // Offer the player a choice of 3 locations: 1 for Moonlight Markets, 2 for Grand Library, and 3 for Shimmer Lake.\n    std::cout \u003C\u003C \"Where will \" \u003C\u003C playerName \u003C\u003C \" go?\" \u003C\u003C std::endl;\n    std::cout \u003C\u003C \"1. Moonlight Markets\" \u003C\u003C std::endl;\n    std::cout \u003C\u003C \"2. Grand Library\" \u003C\u003C std::endl;\n    std::cout \u003C\u003C \"3. Shimmer Lake\" \u003C\u003C std::endl;\n    std::cout \u003C\u003C \"Please enter your choice: \";\n    std::cin >> choice;\n\n```\n\nOnce you start typing `std::cin >>` or accept the prompt for asking the player for their choice, Code Suggestions might offer a suggestion for building out your conditional flow. AI is non-deterministic: One suggestion can involve if/else statements while another solution uses a switch statement.\n\nTo give Code Suggestions a nudge, we'll add a comment and start typing out an if statement: `if (choice ==)`.\n\n![adventure.cpp - Code Suggestions suggests using an if statement to manage choice of locations](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.2-if-statement-locations.png){: .shadow}\n\nAnd if you keep accepting the subsequent suggestions, Code Suggestions will autocomplete the code using if/else statements.\n\n![adventure.cpp - Code Suggestions helps the user fill out the rest of the if/else statements for choosing a location](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.2.1-if-statement-locations-continued.png){: .shadow}\n\n```cpp\n\n    // Check the user's choice and display the corresponding messages\n    if (choice == 1) {\n        std::cout \u003C\u003C \"You chose Moonlight Markets\" \u003C\u003C std::endl;\n    }\n    else if (choice == 2) {\n        std::cout \u003C\u003C \"You chose Grand Library\" \u003C\u003C std::endl;\n    }\n    else if (choice == 3) {\n        std::cout \u003C\u003C \"You chose Shimmer Lake\" \u003C\u003C std::endl;\n    }\n    else {\n        std::cout \u003C\u003C \"Invalid choice\" \u003C\u003C std::endl;\n    }\n\n```\n\n`if/else` is a conditional statement that allows a program to execute code based on whether a condition, in this case the player's choice, is true or false. If the condition evaluates to true, the code inside the braces is executed.\n\n* `if (condition)`: used to check if the condition is true.\n* `else if (another condition)`: if the previous condition isn't true, the programs checks this condition.\n* `else`: if none of the previous conditions are true.\n\nAnother way of managing multiple choices like this example is using a `switch()` statement. A `switch` statement allows our program to jump to different sections of code based on the value of an expression, which, in this case, is the value of `choice`.\n\nWe are going to replace our `if/else` statements with a `switch` statement. You can comment out or delete the `if/else` statements and prompt Code Suggestions starting with `switch(choice) {`.\n\n![adventure.cpp - Code Suggestions helps the user handle the switch statement for the locations](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.3-conditional-switch-locations.png){: .shadow}\n\n![adventure.cpp - Code Suggestions helps the user handle the switch statement for the locations](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.3.1-conditional-switch-locations-continued.png){: .shadow}\n\n```cpp\n\n    // Evaluate the player's decision\n    switch(choice) {\n        // If 'choice' is 1, this block is executed.\n        case 1:\n            std::cout \u003C\u003C \"You chose Moonlight Markets.\" \u003C\u003C std::endl;\n            break;\n        // If 'choice' is 2, this block is executed.\n        case 2:\n            std::cout \u003C\u003C \"You chose Grand Library.\" \u003C\u003C std::endl;\n            break;\n        // If 'choice' is 3, this block is executed.\n        case 3:\n            std::cout \u003C\u003C \"You chose Shimmer Lake.\" \u003C\u003C std::endl;\n            break;\n        // If 'choice' is not 1, 2, or 3, this block is executed.\n        default:\n            std::cout \u003C\u003C \"You did not enter 1, 2, or 3.\" \u003C\u003C std::endl;\n    }\n\n```\n\nEach case represents a potential value that the variable or expression being switched on (in this case, choice) could have. If a match is found, the code for that case is executed. We use the `default` case to handle any input errors in case the player enters a value that isn't accounted for.\n\nLet's build out what happens when our player visits the Shimmering Lake. I've added some comments after the player's arrival at Shimmering Lake to prompt Code Suggestions to help us build this out:\n\n```cpp\n\n    // If 'choice' is 3, this block is executed.\n    case 3:\n        std::cout \u003C\u003C \"You chose Shimmering Lake.\" \u003C\u003C std::endl;\n        // The player arrives at Shimmering Lake. It is one of the most beautiful lakes the player has ever seen.\n        // The player hears a mysterious melody from the water.\n        // They can either 1. Stay quiet and listen, or 2. Sing along with the melody.\n\n        break;\n\n```\n\nNow, if you start writing `std::cout` to begin offering the player this new decision point, Code Suggestions will help fill out the output code.\n\n![adventure.cpp - Code Suggestions helps fill out the output code based on the comments about the interaction at the Lake](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.4-case-3-output.png){: .shadow}\n\nYou might find that the code provided by Code Suggestions is very declarative. Once I've accepted the suggestion, I personalize the code as needed. For example in this case, including the melody the player heard and using the player's name instead of \"you\":\n\n![adventure.cpp - I added the playerName to the output and then prompted Code Suggestions to continue the narrative based on the comments above](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.4.1-customizing-output.png){: .shadow}\n\nI also wanted Code Suggestions to offer suggestions in a specific format, so I added an end line:\n\n![adventure.cpp - I added an end line to prompt Code Suggestions to break the choices into end line outputs](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.4.2-customizing-output-endline.png){: .shadow}\n\n![adventure.cpp - I added an endline to prompt Code Suggestions to break the choices into end line outputs](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.4.3-sub-choices-output.png){: .shadow}\n\nNow, we'd like to offer our player a nested choice in this scenario. Before we can define the new choices, we need a variable to store this nested choice. Let's define a new variable `int nestedChoice` in our `main()` function, outside of the `switch()` statement we set up. You can put it after our definition of the `choice` variable.\n\n```cpp\n\n    // Declare an int variable to capture the user's choice\n    int choice;\n    // Declare an int variable to capture the user's nested choice\n    int nestedChoice;\n\n```\n\nNext, returning to the `if/else` statement we were working on in `case 3`, we want to prompt the player for their decision and save it in `nestedChoice`.\n\n![adventure.cpp - I added an end line to prompt Code Suggestions to break the choices into end line outputs](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.4.4-capture-nested-choice.png){: .shadow}\n\nAs you can see, Code Suggestions wants to go ahead and handle the user's choice using another `switch` statement. I would prefer to use an `if/else` statement to handle this decision point.\n\nFirst, let's add some comments to give context:\n\n```cpp\n\n    // Capture the user's nested choice\n    std::cin >> nestedChoice;\n\n    // If the player chooses 1 and remains silent, they hear whispers of the merfolk below, but nothing happens.\n    // If the player chooses 2 and sings along, a merfolk surfaces and gifts them a special blue gem as a token of appreciation for their voice.\n\n    // Evaluate the user's nestedChoice\n\n```\n\nThen, start typing `if (nestedChoice == 1)` and Code Suggestions will start to offer suggestions:\n\n![adventure.cpp - Code Suggestions starts to build out an if statement to handle the nestedChoice](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.5-nested-choice-if.png){: .shadow}\n\nIf you tab to accept them, Code Suggestions will continue to fill out the rest of the nested `if/else` statements.\n\nSometimes, while you're customizing the suggestions that Code Suggestions gives, you may even discover that it would like to make creative suggestions, too!\n\n![adventure.cpp - Code Suggestions makes a creative suggestion to end the interaction with the merfolk by saying \"You are now free to go\" after you receive the gem.](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.5.2-nested-cs-creative-suggestion.png){: .shadow}\n\nHere's the code for `case 3` for the player's interaction at Shimmering Lake with the nested decision. I've updated some of the narrative dialogue player's name.\n```text\n\n    // Handle the Shimmering Lake scenario.\n    case 3:\n        std::cout \u003C\u003C playerName \u003C\u003C \" arrives at Shimmering Lake. It is one of the most beautiful lakes that\" \u003C\u003C playerName \u003C\u003C \" has seen. They hear a mysterious melody from the water. They can either: \" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"1. Stay quiet and listen\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"2. Sing along with the melody\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Please enter your choice: \";\n\n        // Capture the user's nested choice\n        std::cin >> nestedChoice;\n\n        // If the player chooses to remain silent\n        if (nestedChoice == 1)\n        {\n            std::cout \u003C\u003C \"Remaining silent, \" \u003C\u003C playerName \u003C\u003C \" hears whispers of the merfolk below, but nothing happens.\" \u003C\u003C std::endl;\n        }\n        // If the player chooses to sing along with the melody\n        else if (nestedChoice == 2)\n        {\n            std::cout \u003C\u003C \"Singing along, a merfolk surfaces and gifts \" \u003C\u003C playerName\n                    \u003C\u003C \" a special blue gem as a token of appreciation for their voice.\"\n                    \u003C\u003C std::endl;\n        }\n        break;\n\n```\n\nOur player isn't limited to just exploring Shimmering Lake. There's a whole realm to explore and they might want to go back and explore other locations.\n\nTo facilitate this, we can use a `while` loop. A loop is a type of conditional that allows a specific section of code to be executed multiple times based on a condition. For the `condition` that allows our `while` loop to run multiple times, let's use a `boolean` to initialize the loop condition.\n\n```cpp\n\n    // Initialize a flag to control the loop and signify the player's intent to explore.\n    bool exploring = true;\n    // As long as the player wishes to keep exploring, this loop will run.\n    while(exploring) {\n        // wrap the code for switch(choice)\n    }\n\n```\n\nWe also need to move our location prompt inside the `while` loop so that the player can visit more than one location at the time.\n\n![adventure.cpp - CS helps us write a go next prompt for the locations](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.6-while-loop-go-next.png){: .shadow}\n\n```cpp\n\n    // Initialize a flag to control the loop and signify the player's intent to explore.\n    bool exploring = true;\n    // As long as the player wishes to keep exploring, this loop will run.\n    while(exploring) {\n\n        // If still exploring, ask the player where they want to go next\n        std::cout \u003C\u003C \"Where will \" \u003C\u003C playerName \u003C\u003C \" go next?\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"1. Moonlight Markets\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"2. Grand Library\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"3. Shimmering Lake\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Please enter your choice: \";\n        // Update value of choice\n        std::cin >> choice;\n\n        // Respond based on the player's main choice\n        switch(choice) {\n\n```\n\nOur `while` loop will keep running as long as `exploring` is `true`, so we need a way for the player to have the option to exit the game. Let's add a case 4 that allows the player to exit by setting `exploring = false`. This will exit the loop and take the player back to the original choices.\n\n```cpp\n\n    // Option to exit the game\n    case 4:\n        exploring = false;\n        break;\n\n```\n\n**Async exercise**: Give the player the option to exit the game instead of exploring a new decision.\n\nWe also need to update the error handling for invalid inputs in the `switch` statement. You can decide whether to end the program or use the `continue` statement to start a new loop iteration.\n\n```cpp\n\n        default:\n            std::cout \u003C\u003C \"You did not enter a valid choice.\" \u003C\u003C std::endl;\n            continue; // Errors continue with the next loop iteration\n\n```\n\nUsing I/O and conditionals is at the core of text-based adventure games and helps make these games interactive. We can combine user input, display output, and implement our narrative into decision-making logic to create an engaging experience.\n\nHere's what our `adventure.cpp` looks like now with some comments:\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Main function, the starting point of the program\nint main()\n{\n    std::cout \u003C\u003C \"Welcome to the Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Declare a string variable to store the player name\n    std::string playerName;\n\n    // Prompt the user to enter their player name\n    std::cout \u003C\u003C \"Please enter your name: \";\n    std::cin >> playerName;\n\n    // Display a personalized welcome message to the player with their name\n    std::cout \u003C\u003C \"Welcome \" \u003C\u003C playerName \u003C\u003C \" to The Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Declare an int variable to capture the user's choice\n    int choice;\n    // Declare an int variable to capture the user's nested choice\n    int nestedChoice;\n\n    // Initialize a flag to control the loop and signify the player's intent to explore.\n    bool exploring = true;\n    // As long as the player wishes to keep exploring, this loop will run.\n    while(exploring) {\n\n        // If still exploring, ask the player where they want to go next\n        std::cout \u003C\u003C \"Where will \" \u003C\u003C playerName \u003C\u003C \" go next?\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"1. Moonlight Markets\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"2. Grand Library\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"3. Shimmering Lake\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Please enter your choice: \";\n        // Update value of choice\n        std::cin >> choice;\n\n        // Respond based on the player's main choice\n        switch(choice) {\n            //  Handle the Moonlight Markets scenario\n            case 1:\n                std::cout \u003C\u003C \"You chose Moonlight Markets.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Grand Library scenario.\n            case 2:\n                std::cout \u003C\u003C \"You chose Grand Library.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Shimmering Lake scenario.\n            case 3:\n                std::cout \u003C\u003C playerName \u003C\u003C \" arrives at Shimmering Lake. It is one of the most beautiful lakes that\" \u003C\u003C playerName \u003C\u003C \" has seen. They hear a mysterious melody from the water. They can either: \" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"1. Stay quiet and listen\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"2. Sing along with the melody\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"Please enter your choice: \";\n\n                // Capture the user's nested choice\n                std::cin >> nestedChoice;\n\n                // If the player chooses to remain silent\n                if (nestedChoice == 1)\n                {\n                    std::cout \u003C\u003C \"Remaining silent, \" \u003C\u003C playerName \u003C\u003C \" hears whispers of the merfolk below, but nothing happens.\" \u003C\u003C std::endl;\n                }\n                // If the player chooses to sing along with the melody\n                else if (nestedChoice == 2)\n                {\n                    std::cout \u003C\u003C \"Singing along, a merfolk surfaces and gifts \" \u003C\u003C playerName\n                            \u003C\u003C \" a special blue gem as a token of appreciation for their voice.\"\n                            \u003C\u003C std::endl;\n                }\n                break;\n            // Option to exit the game\n            case 4:\n                exploring = false;\n                break;\n            // If 'choice' is not 1, 2, or 3, this block is executed.\n            default:\n                std::cout \u003C\u003C \"You did not enter a valid choice.\" \u003C\u003C std::endl;\n                continue; // Errors continue with the next loop iteration\n        }\n    }\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\nHere's what the build output looks like if we run `adventure.cpp` and the player heads to the Shimmering Lake.\n\n![adventure.cpp build output - the player is called sugaroverflow and heads to the Shimmering Lake and receives a gem](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/3.6.1-full-case-3-output.png){: .shadow}\n\n## Structuring the narrative: Characters\nOur player can now explore the world. Soon, our player will also be able to meet people and collect objects. Before we can do that, let's organize the things our player can do with creating some structure for the player character.\n\nIn C++, a `struct` is used to group different data types. It's helpful in creating a group of items that belong together, such as our player's attributes and inventory, into a single unit. `struct` objects are defined globally, which means at top the file, before the `main() function.\n\nIf you start typing `struct Player {`, Code Suggestions will help you out with a sample definition of a player struct.\n\n![adventure.cpp - Code Suggestions helps with setting up the struct definition for the player](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/4-player-struct-definition.png){: .shadow}\n\nAfter accepting this suggestion, you might find that Code Suggestions is eager to define some functions to make this game more fun, such as hunting for treasure.\n\n![adventure.cpp - Code Suggestions provides a suggestion for creating functions to hunt for treasure.](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/4.1-player-struct-treasure-suggestion.png){: .shadow}\n\n```cpp\n// Define a structure for a Player in the game.\nstruct Player{\n    std::string name;  // The name of the player.\n    int health;        // The current health of the player.\n    int xp;            // Experience points gained by the player. Could be used for leveling up or other game mechanics.\n};\n```\n\nGiving the player experience points was not in my original plan for this text adventure game, but Code Suggestions makes an interesting suggestion. We could use `xp` for leveling up or for other game mechanics as our project grows.\n\n`struct Player` provides a blueprint for creating a player and details the attributes that make up a player. To use our player in our code, we must instantiate, or create, an object of the `Player` struct within our `main()` function. Objects in C++ are instances of structures that contain attributes. In our example, we're working with the `Player` struct, which has attributes like name, health, and xp.\n\nAs you're creating a `Player` object, you might find that Code Suggestions wants to name the player \"John.\"\n\n![adventure.cpp - code suggestions suggests naming the new Player object John.](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/4.2-player-struct-instance-john.png){: .shadow}\n\n```cpp\nint main() {\n    // Create an instance of the Player struct\n    Player player;\n    player.health = 100; // Assign a default value for HP\n\n```\n\nInstead of naming our player \"John\" for everyone, we'll use the `Player` object to set the attribute for name. When we want to interact with or manipulate an attribute of an object, we use the dot operator `.`. The dot operator allows us to access specific members of the object. We can set the player's name using the dot operator with `player.name`.\n\nNote that we need to replace other mentions of `playerName` the variable with `player.name`, which allows us to access the player object's name directly.\n\n* Search for all occurrences of the `playerName` variable, and replace it with `player.name`.\n* Comment/Remove the unused `std::string playerName` variable after that.\n\nWhat your `adventure.cpp` will look like now:\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Define a structure for a Player in the game.\nstruct Player{\n    std::string name;  // The name of the player.\n    int health;        // The current health of the player.\n    int xp;            // Experience points gained by the player. Could be used for leveling up or other game mechanics.\n};\n\n// Main function, the starting point of the program\nint main()\n{\n    std::cout \u003C\u003C \"Welcome to the Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Create an instance of the Player struct\n    Player player;\n    player.health = 100; // Assign a default value for HP\n\n    // Prompt the user to enter their player name\n    std::cout \u003C\u003C \"Please enter your name: \";\n    std::cin >> player.name;\n\n    // Display a personalized welcome message to the player with their name\n    std::cout \u003C\u003C \"Welcome \" \u003C\u003C player.name \u003C\u003C \" to The Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Declare an int variable to capture the user's choice\n    int choice;\n    // Declare an int variable to capture the user's nested choice\n    int nestedChoice;\n\n    // Initialize a flag to control the loop and signify the player's intent to explore.\n    bool exploring = true;\n    // As long as the player wishes to keep exploring, this loop will run.\n    while(exploring) {\n\n        // If still exploring, ask the player where they want to go next\n        std::cout \u003C\u003C \"Where will \" \u003C\u003C player.name \u003C\u003C \" go next?\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"1. Moonlight Markets\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"2. Grand Library\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"3. Shimmering Lake\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Please enter your choice: \";\n        // Update value of choice\n        std::cin >> choice;\n\n        // Respond based on the player's main choice\n        switch(choice) {\n            //  Handle the Moonlight Markets scenario\n            case 1:\n                std::cout \u003C\u003C \"You chose Moonlight Markets.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Grand Library scenario.\n            case 2:\n                std::cout \u003C\u003C \"You chose Grand Library.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Shimmering Lake scenario.\n            case 3:\n                std::cout \u003C\u003C player.name \u003C\u003C \" arrives at Shimmering Lake. It is one of the most beautiful lakes that\" \u003C\u003C player.name \u003C\u003C \" has seen. They hear a mysterious melody from the water. They can either: \" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"1. Stay quiet and listen\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"2. Sing along with the melody\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"Please enter your choice: \";\n\n                // Capture the user's nested choice\n                std::cin >> nestedChoice;\n\n                // If the player chooses to remain silent\n                if (nestedChoice == 1)\n                {\n                    std::cout \u003C\u003C \"Remaining silent, \" \u003C\u003C player.name \u003C\u003C \" hears whispers of the merfolk below, but nothing happens.\" \u003C\u003C std::endl;\n                }\n                // If the player chooses to sing along with the melody\n                else if (nestedChoice == 2)\n                {\n                    std::cout \u003C\u003C \"Singing along, a merfolk surfaces and gifts \" \u003C\u003C player.name\n                            \u003C\u003C \" a special blue gem as a token of appreciation for their voice.\"\n                            \u003C\u003C std::endl;\n                }\n                break;\n            // Option to exit the game\n            case 4:\n                exploring = false;\n                break;\n            // If 'choice' is not 1, 2, or 3, this block is executed.\n            default:\n                std::cout \u003C\u003C \"You did not enter a valid choice.\" \u003C\u003C std::endl;\n                continue; // Errors continue with the next loop iteration\n        }\n    }\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\n## Structuring the narrative: Items\nAn essential part of adventure games is a player's inventory - the collection of items they acquire and use during their journey. For example, at Shimmering Lake, the player acquired a blue gem.\n\nLet's update our Player `struct` to include an inventory using an array. In C++, an `array` is a collection of elements of the same type that can be identified by an index. When creating an array, you need to specify its type and size. Start by adding `std::string inventory` to the Player `struct`:\n\n![adventure.cpp - Code Suggestions shows us how to add an array of strings to the player struct to use as the players inventory](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5-add-inventory-player-struct.png){: .shadow}\n\nYou might find that Code Suggestions wants our player to be able to carry some gold, but we don't need that for now. Let's also add `int inventoryCount;` to keep track of the number of items in our player's inventory.\n\n![adventure.cpp - Code Suggestions shows us how to add an integer for inventoryCount to the player struct](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5.1-add-inventory-count-player-struct.png){: .shadow}\n\n```cpp\n// Define a structure for a Player in the game.\nstruct Player{\n    std::string name;  // The name of the player.\n    int health;        // The current health of the player.\n    int xp;            // Experience points gained by the player. Could be used for leveling up or other game mechanics.\n    std::string inventory[10];  // An array of strings for the player's inventory.\n    int inventoryCount = 0;  // The number of items in the player's inventory.\n};\n```\nIn our Player `struct`, we have defined an array for our inventory that can hold the names of 10 items (type:string, size: 10). As the player progresses through our story, we can assign new items to the inventory array based on the player's actions using the array index.\n\nSometimes Code Suggestions gets ahead of me and tries to add more complexity to the game by suggesting that we need to create a `struct` for some Monsters. Maybe later, Code Suggestions!\n\n![adventure.cpp - Code Suggestions wants to add a struct for Monsters we can battle](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5.2-suggestion-gets-distracted-by-monsters.png\n)\n\nBack at the Shimmering Lake, the player received a special blue gem from the merfolk. Let's update the code in `case 2` for the Shimmering Lake to add the gem to our player's inventory.\n\nYou can start by accessing the player's inventory with `player.inventory` and Code Suggestions will help add the gem.\n\n![adventure.cpp - Code Suggestions shows us how to add a gem to the player's inventory using a post-increment operation and the inventory array from the struct object](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5.3-add-gem-to-inventory.png){: .shadow}\n\n```cpp\n\n    // If the player chooses to sing along with the melody\n    else if (nestedChoice == 2)\n    {\n        std::cout \u003C\u003C \"Singing along, a merfolk surfaces and gifts \" \u003C\u003C player.name\n                \u003C\u003C \" a special blue gem as a token of appreciation for their voice.\"\n                \u003C\u003C std::endl;\n        player.inventory[player.inventoryCount] = \"Blue Gem\";\n        player.inventoryCount++;\n    }\n\n```\n\n* `player.inventory`: accesses the inventory attribute of the player object\n* `player.inventoryCount`: accesses the integer that keeps track of how many items are currently in the player's inventory. This also represents the next available index in our inventory array where an item can be stored.\n* `player.inventoryCount++`: increments the value of inventoryCount by 1. This is a post-increment operation. We are adding “Blue Gem” to the next available slot in the inventory array and incrementing the array for the newly added item.\n\nOnce we've added something to our player's inventory, we may also want to be able to look at everything in the inventory. We can use a `for` loop to iterate over the inventory array and display each item.\n\nIn C++, a `for` loop allows code to be repeatedly executed a specific number of times. It's different from the `while` loop we used earlier because the `while` executes its body based on a condition, whereas a `for` loop iterates over a sequence or range, usually with a known number of times.\n\nAfter adding the gem to the player's inventory, let's display all the items it has. Try starting a for loop with `for ( ` to display the player's inventory and Code Suggestions will help you with the syntax.\n\n![adventure.cpp - Code Suggestions demonstrates how to write a for loop to loop through the players inventory](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5.4-loop-over-players-inventory.png){: .shadow}\n\n```cpp\nstd::cout \u003C\u003C player.name \u003C\u003C \"'s Inventory:\" \u003C\u003C std::endl;\n// Loop through the player's inventory up to the count of items they have\nfor (int i = 0; i \u003C player.inventoryCount; i++)\n{\n    // Output the item in the inventory slot\n    std::cout \u003C\u003C \"- \" \u003C\u003C player.inventory[i] \u003C\u003C std::endl;\n}\n```\n\nA `for` loop consists of 3 main parts:\n\n* `int i = 0`: is the initialization where you set up your loop variable. Here, we start counting from 0.\n* `i \u003C player.inventoryCount`: is the condition we're looping on, our loop checks if `i`, the current loop variable, is less than the number of items in our inventory. It will keep going until this is true.\n* `i++`: is the iteration. This updates the loop variable each time the loop runs.\n\nTo make sure that our loop doesn't encounter an error, let's add some error handling to make sure the inventory is not empty when we try to output it.\n\n```text\nstd::cout \u003C\u003C player.name \u003C\u003C \"'s Inventory:\" \u003C\u003C std::endl;\n// Loop through the player's inventory up to the count of items they have\nfor (int i = 0; i \u003C player.inventoryCount; i++)\n{\n    // Check if the inventory slot is not empty.\n    if (!player.inventory[i].empty())\n    {\n        // Output the item in the inventory slot\n        std::cout \u003C\u003C \"- \" \u003C\u003C player.inventory[i] \u003C\u003C std::endl;\n    }\n}\n```\n\nWith our progress so far, we've successfully established a persistent `while` loop for our adventure, handled decisions, crafted a `struct` for our player, and implemented a simple inventory system. Now, let's dive into the next scenario, the Grand Library, applying the foundations we've learned.\n\n**Async exercise**: Add more inventory items found in different locations.\n\nHere's what we have for `adventure.cpp` so far:\n\n```cpp\n#include \u003Ciostream> // Include the I/O stream library for input and output\n\n// Define a structure for a Player in the game.\nstruct Player{\n    std::string name;  // The name of the player.\n    int health;        // The current health of the player.\n    int xp;            // Experience points gained by the player. Could be used for leveling up or other game mechanics.\n    std::string inventory[10];  // An array of strings for the player's inventory.\n    int inventoryCount = 0;\n};\n\n// Main function, the starting point of the program\nint main()\n{\n    std::cout \u003C\u003C \"Welcome to the Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Create an instance of the Player struct\n    Player player;\n    player.health = 100; // Assign a default value for HP\n\n    // Prompt the user to enter their player name\n    std::cout \u003C\u003C \"Please enter your name: \";\n    std::cin >> player.name;\n\n    // Display a personalized welcome message to the player with their name\n    std::cout \u003C\u003C \"Welcome \" \u003C\u003C player.name \u003C\u003C \" to The Dragon Realm!\" \u003C\u003C std::endl;\n\n    // Declare an int variable to capture the user's choice\n    int choice;\n    // Declare an int variable to capture the user's nested choice\n    int nestedChoice;\n\n    // Initialize a flag to control the loop and signify the player's intent to explore.\n    bool exploring = true;\n    // As long as the player wishes to keep exploring, this loop will run.\n    while(exploring) {\n\n        // If still exploring, ask the player where they want to go next\n        std::cout \u003C\u003C \"--------------------------------------------------------\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Where will \" \u003C\u003C player.name \u003C\u003C \" go next?\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"1. Moonlight Markets\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"2. Grand Library\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"3. Shimmering Lake\" \u003C\u003C std::endl;\n        std::cout \u003C\u003C \"Please enter your choice: \";\n        // Update value of choice\n        std::cin >> choice;\n\n        // Respond based on the player's main choice\n        switch(choice) {\n            //  Handle the Moonlight Markets scenario\n            case 1:\n                std::cout \u003C\u003C \"You chose Moonlight Markets.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Grand Library scenario.\n            case 2:\n                std::cout \u003C\u003C \"You chose Grand Library.\" \u003C\u003C std::endl;\n                break;\n            // Handle the Shimmering Lake scenario.\n            case 3:\n                std::cout \u003C\u003C player.name \u003C\u003C \" arrives at Shimmering Lake. It is one of the most beautiful lakes that\" \u003C\u003C player.name \u003C\u003C \" has seen. They hear a mysterious melody from the water. They can either: \" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"1. Stay quiet and listen\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"2. Sing along with the melody\" \u003C\u003C std::endl;\n                std::cout \u003C\u003C \"Please enter your choice: \";\n\n                // Capture the user's nested choice\n                std::cin >> nestedChoice;\n\n                // If the player chooses to remain silent\n                if (nestedChoice == 1)\n                {\n                    std::cout \u003C\u003C \"Remaining silent, \" \u003C\u003C player.name \u003C\u003C \" hears whispers of the merfolk below, but nothing happens.\" \u003C\u003C std::endl;\n                }\n                // If the player chooses to sing along with the melody\n                else if (nestedChoice == 2)\n                {\n                    std::cout \u003C\u003C \"Singing along, a merfolk surfaces and gifts \" \u003C\u003C player.name\n                            \u003C\u003C \" a special blue gem as a token of appreciation for their voice.\"\n                            \u003C\u003C std::endl;\n                    player.inventory[player.inventoryCount] = \"Blue Gem\";\n                    player.inventoryCount++;\n\n                    std::cout \u003C\u003C player.name \u003C\u003C \"'s Inventory:\" \u003C\u003C std::endl;\n                    // Loop through the player's inventory up to the count of items they have\n                    for (int i = 0; i \u003C player.inventoryCount; i++)\n                    {\n                        // Check if the inventory slot is not empty.\n                        if (!player.inventory[i].empty())\n                        {\n                            // Output the item in the inventory slot\n                            std::cout \u003C\u003C \"- \" \u003C\u003C player.inventory[i] \u003C\u003C std::endl;\n                        }\n                    }\n\n                }\n                break;\n            // Option to exit the game\n            case 4:\n                exploring = false;\n                break;\n            // If 'choice' is not 1, 2, or 3, this block is executed.\n            default:\n                std::cout \u003C\u003C \"You did not enter a valid choice.\" \u003C\u003C std::endl;\n                continue; // Errors continue with the next loop iteration\n        }\n    }\n\n    // Return 0 to indicate successful execution\n    return 0;\n}\n```\n\n![adventure.cpp - A full output of the game at the current state - our player sugaroverflow visits the Lake, receives the gem, adds it to their inventory, and we display the inventory before returning to the loop](https://about.gitlab.com/images/blogimages/2023-08-21-building-a-text-adventure-using-cplusplus-and-code-suggestions/5.5-full-output-shimmering-lake.png){: .shadow}\n",[23,24,25,26,27],"DevSecOps platform","AI/ML","workflow","DevSecOps","tutorial","yml",{},true,"/en-us/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions",{"title":33,"description":16,"ogTitle":33,"ogDescription":16,"noIndex":12,"ogImage":19,"ogUrl":34,"ogSiteName":35,"ogType":36,"canonicalUrls":34},"Explore the Dragon Realm: Building a C++ adventure game with AI","https://about.gitlab.com/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions","https://about.gitlab.com","article","en-us/blog/building-a-text-adventure-using-cplusplus-and-code-suggestions",[39,40,25,41,27],"devsecops-platform","aiml","devsecops","wqdBvlkYhEQXtUpYU5fdUp_JMSzthmJGWCEaecVY6DA",{"data":44},{"logo":45,"freeTrial":50,"sales":55,"login":60,"items":65,"search":373,"minimal":404,"duo":423,"switchNav":432,"pricingDeployment":443},{"config":46},{"href":47,"dataGaName":48,"dataGaLocation":49},"/","gitlab logo","header",{"text":51,"config":52},"Get free trial",{"href":53,"dataGaName":54,"dataGaLocation":49},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":56,"config":57},"Talk to sales",{"href":58,"dataGaName":59,"dataGaLocation":49},"/sales/","sales",{"text":61,"config":62},"Sign in",{"href":63,"dataGaName":64,"dataGaLocation":49},"https://gitlab.com/users/sign_in/","sign in",[66,93,188,193,294,354],{"text":67,"config":68,"cards":70},"Platform",{"dataNavLevelOne":69},"platform",[71,77,85],{"title":67,"description":72,"link":73},"The intelligent orchestration platform for DevSecOps",{"text":74,"config":75},"Explore our Platform",{"href":76,"dataGaName":69,"dataGaLocation":49},"/platform/",{"title":78,"description":79,"link":80},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":81,"config":82},"Meet GitLab Duo",{"href":83,"dataGaName":84,"dataGaLocation":49},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":86,"description":87,"link":88},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":89,"config":90},"Learn more",{"href":91,"dataGaName":92,"dataGaLocation":49},"/why-gitlab/","why gitlab",{"text":94,"left":30,"config":95,"link":97,"lists":101,"footer":170},"Product",{"dataNavLevelOne":96},"solutions",{"text":98,"config":99},"View all Solutions",{"href":100,"dataGaName":96,"dataGaLocation":49},"/solutions/",[102,126,149],{"title":103,"description":104,"link":105,"items":110},"Automation","CI/CD and automation to accelerate deployment",{"config":106},{"icon":107,"href":108,"dataGaName":109,"dataGaLocation":49},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[111,115,118,122],{"text":112,"config":113},"CI/CD",{"href":114,"dataGaLocation":49,"dataGaName":112},"/solutions/continuous-integration/",{"text":78,"config":116},{"href":83,"dataGaLocation":49,"dataGaName":117},"gitlab duo agent platform - product menu",{"text":119,"config":120},"Source Code Management",{"href":121,"dataGaLocation":49,"dataGaName":119},"/solutions/source-code-management/",{"text":123,"config":124},"Automated Software Delivery",{"href":108,"dataGaLocation":49,"dataGaName":125},"Automated software delivery",{"title":127,"description":128,"link":129,"items":134},"Security","Deliver code faster without compromising security",{"config":130},{"href":131,"dataGaName":132,"dataGaLocation":49,"icon":133},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[135,139,144],{"text":136,"config":137},"Application Security Testing",{"href":131,"dataGaName":138,"dataGaLocation":49},"Application security testing",{"text":140,"config":141},"Software Supply Chain Security",{"href":142,"dataGaLocation":49,"dataGaName":143},"/solutions/supply-chain/","Software supply chain security",{"text":145,"config":146},"Software Compliance",{"href":147,"dataGaName":148,"dataGaLocation":49},"/solutions/software-compliance/","software compliance",{"title":150,"link":151,"items":156},"Measurement",{"config":152},{"icon":153,"href":154,"dataGaName":155,"dataGaLocation":49},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[157,161,165],{"text":158,"config":159},"Visibility & Measurement",{"href":154,"dataGaLocation":49,"dataGaName":160},"Visibility and Measurement",{"text":162,"config":163},"Value Stream Management",{"href":164,"dataGaLocation":49,"dataGaName":162},"/solutions/value-stream-management/",{"text":166,"config":167},"Analytics & Insights",{"href":168,"dataGaLocation":49,"dataGaName":169},"/solutions/analytics-and-insights/","Analytics and insights",{"title":171,"items":172},"GitLab for",[173,178,183],{"text":174,"config":175},"Enterprise",{"href":176,"dataGaLocation":49,"dataGaName":177},"/enterprise/","enterprise",{"text":179,"config":180},"Small Business",{"href":181,"dataGaLocation":49,"dataGaName":182},"/small-business/","small business",{"text":184,"config":185},"Public Sector",{"href":186,"dataGaLocation":49,"dataGaName":187},"/solutions/public-sector/","public sector",{"text":189,"config":190},"Pricing",{"href":191,"dataGaName":192,"dataGaLocation":49,"dataNavLevelOne":192},"/pricing/","pricing",{"text":194,"config":195,"link":197,"lists":201,"feature":281},"Resources",{"dataNavLevelOne":196},"resources",{"text":198,"config":199},"View all resources",{"href":200,"dataGaName":196,"dataGaLocation":49},"/resources/",[202,235,253],{"title":203,"items":204},"Getting started",[205,210,215,220,225,230],{"text":206,"config":207},"Install",{"href":208,"dataGaName":209,"dataGaLocation":49},"/install/","install",{"text":211,"config":212},"Quick start guides",{"href":213,"dataGaName":214,"dataGaLocation":49},"/get-started/","quick setup checklists",{"text":216,"config":217},"Learn",{"href":218,"dataGaLocation":49,"dataGaName":219},"https://university.gitlab.com/","learn",{"text":221,"config":222},"Product documentation",{"href":223,"dataGaName":224,"dataGaLocation":49},"https://docs.gitlab.com/","product documentation",{"text":226,"config":227},"Best practice videos",{"href":228,"dataGaName":229,"dataGaLocation":49},"/getting-started-videos/","best practice videos",{"text":231,"config":232},"Integrations",{"href":233,"dataGaName":234,"dataGaLocation":49},"/integrations/","integrations",{"title":236,"items":237},"Discover",[238,243,248],{"text":239,"config":240},"Customer success stories",{"href":241,"dataGaName":242,"dataGaLocation":49},"/customers/","customer success stories",{"text":244,"config":245},"Blog",{"href":246,"dataGaName":247,"dataGaLocation":49},"/blog/","blog",{"text":249,"config":250},"Remote",{"href":251,"dataGaName":252,"dataGaLocation":49},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":254,"items":255},"Connect",[256,261,266,271,276],{"text":257,"config":258},"GitLab Services",{"href":259,"dataGaName":260,"dataGaLocation":49},"/services/","services",{"text":262,"config":263},"Community",{"href":264,"dataGaName":265,"dataGaLocation":49},"/community/","community",{"text":267,"config":268},"Forum",{"href":269,"dataGaName":270,"dataGaLocation":49},"https://forum.gitlab.com/","forum",{"text":272,"config":273},"Events",{"href":274,"dataGaName":275,"dataGaLocation":49},"/events/","events",{"text":277,"config":278},"Partners",{"href":279,"dataGaName":280,"dataGaLocation":49},"/partners/","partners",{"backgroundColor":282,"textColor":283,"text":284,"image":285,"link":289},"#2f2a6b","#fff","Insights for the future of software development",{"altText":286,"config":287},"the source promo card",{"src":288},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":290,"config":291},"Read the latest",{"href":292,"dataGaName":293,"dataGaLocation":49},"/the-source/","the source",{"text":295,"config":296,"lists":298},"Company",{"dataNavLevelOne":297},"company",[299],{"items":300},[301,306,312,314,319,324,329,334,339,344,349],{"text":302,"config":303},"About",{"href":304,"dataGaName":305,"dataGaLocation":49},"/company/","about",{"text":307,"config":308,"footerGa":311},"Jobs",{"href":309,"dataGaName":310,"dataGaLocation":49},"/jobs/","jobs",{"dataGaName":310},{"text":272,"config":313},{"href":274,"dataGaName":275,"dataGaLocation":49},{"text":315,"config":316},"Leadership",{"href":317,"dataGaName":318,"dataGaLocation":49},"/company/team/e-group/","leadership",{"text":320,"config":321},"Team",{"href":322,"dataGaName":323,"dataGaLocation":49},"/company/team/","team",{"text":325,"config":326},"Handbook",{"href":327,"dataGaName":328,"dataGaLocation":49},"https://handbook.gitlab.com/","handbook",{"text":330,"config":331},"Investor relations",{"href":332,"dataGaName":333,"dataGaLocation":49},"https://ir.gitlab.com/","investor relations",{"text":335,"config":336},"Trust Center",{"href":337,"dataGaName":338,"dataGaLocation":49},"/security/","trust center",{"text":340,"config":341},"AI Transparency Center",{"href":342,"dataGaName":343,"dataGaLocation":49},"/ai-transparency-center/","ai transparency center",{"text":345,"config":346},"Newsletter",{"href":347,"dataGaName":348,"dataGaLocation":49},"/company/contact/#contact-forms","newsletter",{"text":350,"config":351},"Press",{"href":352,"dataGaName":353,"dataGaLocation":49},"/press/","press",{"text":355,"config":356,"lists":357},"Contact us",{"dataNavLevelOne":297},[358],{"items":359},[360,363,368],{"text":56,"config":361},{"href":58,"dataGaName":362,"dataGaLocation":49},"talk to sales",{"text":364,"config":365},"Support portal",{"href":366,"dataGaName":367,"dataGaLocation":49},"https://support.gitlab.com","support portal",{"text":369,"config":370},"Customer portal",{"href":371,"dataGaName":372,"dataGaLocation":49},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":374,"login":375,"suggestions":382},"Close",{"text":376,"link":377},"To search repositories and projects, login to",{"text":378,"config":379},"gitlab.com",{"href":63,"dataGaName":380,"dataGaLocation":381},"search login","search",{"text":383,"default":384},"Suggestions",[385,387,391,393,397,401],{"text":78,"config":386},{"href":83,"dataGaName":78,"dataGaLocation":381},{"text":388,"config":389},"Code Suggestions (AI)",{"href":390,"dataGaName":388,"dataGaLocation":381},"/solutions/code-suggestions/",{"text":112,"config":392},{"href":114,"dataGaName":112,"dataGaLocation":381},{"text":394,"config":395},"GitLab on AWS",{"href":396,"dataGaName":394,"dataGaLocation":381},"/partners/technology-partners/aws/",{"text":398,"config":399},"GitLab on Google Cloud",{"href":400,"dataGaName":398,"dataGaLocation":381},"/partners/technology-partners/google-cloud-platform/",{"text":402,"config":403},"Why GitLab?",{"href":91,"dataGaName":402,"dataGaLocation":381},{"freeTrial":405,"mobileIcon":410,"desktopIcon":415,"secondaryButton":418},{"text":406,"config":407},"Start free trial",{"href":408,"dataGaName":54,"dataGaLocation":409},"https://gitlab.com/-/trials/new/","nav",{"altText":411,"config":412},"Gitlab Icon",{"src":413,"dataGaName":414,"dataGaLocation":409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":411,"config":416},{"src":417,"dataGaName":414,"dataGaLocation":409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":419,"config":420},"Get Started",{"href":421,"dataGaName":422,"dataGaLocation":409},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":424,"mobileIcon":428,"desktopIcon":430},{"text":425,"config":426},"Learn more about GitLab Duo",{"href":83,"dataGaName":427,"dataGaLocation":409},"gitlab duo",{"altText":411,"config":429},{"src":413,"dataGaName":414,"dataGaLocation":409},{"altText":411,"config":431},{"src":417,"dataGaName":414,"dataGaLocation":409},{"button":433,"mobileIcon":438,"desktopIcon":440},{"text":434,"config":435},"/switch",{"href":436,"dataGaName":437,"dataGaLocation":409},"#contact","switch",{"altText":411,"config":439},{"src":413,"dataGaName":414,"dataGaLocation":409},{"altText":411,"config":441},{"src":442,"dataGaName":414,"dataGaLocation":409},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":444,"mobileIcon":449,"desktopIcon":451},{"text":445,"config":446},"Back to pricing",{"href":191,"dataGaName":447,"dataGaLocation":409,"icon":448},"back to pricing","GoBack",{"altText":411,"config":450},{"src":413,"dataGaName":414,"dataGaLocation":409},{"altText":411,"config":452},{"src":417,"dataGaName":414,"dataGaLocation":409},{"title":454,"button":455,"config":460},"See how agentic AI transforms software delivery",{"text":456,"config":457},"Watch GitLab Transcend now",{"href":458,"dataGaName":459,"dataGaLocation":49},"/events/transcend/virtual/","transcend event",{"layout":461,"icon":462,"disabled":30},"release","AiStar",{"data":464},{"text":465,"source":466,"edit":472,"contribute":477,"config":482,"items":487,"minimal":691},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":467,"config":468},"View page source",{"href":469,"dataGaName":470,"dataGaLocation":471},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":473,"config":474},"Edit this page",{"href":475,"dataGaName":476,"dataGaLocation":471},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":478,"config":479},"Please contribute",{"href":480,"dataGaName":481,"dataGaLocation":471},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":483,"facebook":484,"youtube":485,"linkedin":486},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[488,535,586,630,657],{"title":189,"links":489,"subMenu":504},[490,494,499],{"text":491,"config":492},"View plans",{"href":191,"dataGaName":493,"dataGaLocation":471},"view plans",{"text":495,"config":496},"Why Premium?",{"href":497,"dataGaName":498,"dataGaLocation":471},"/pricing/premium/","why premium",{"text":500,"config":501},"Why Ultimate?",{"href":502,"dataGaName":503,"dataGaLocation":471},"/pricing/ultimate/","why ultimate",[505],{"title":506,"links":507},"Contact Us",[508,511,513,515,520,525,530],{"text":509,"config":510},"Contact sales",{"href":58,"dataGaName":59,"dataGaLocation":471},{"text":364,"config":512},{"href":366,"dataGaName":367,"dataGaLocation":471},{"text":369,"config":514},{"href":371,"dataGaName":372,"dataGaLocation":471},{"text":516,"config":517},"Status",{"href":518,"dataGaName":519,"dataGaLocation":471},"https://status.gitlab.com/","status",{"text":521,"config":522},"Terms of use",{"href":523,"dataGaName":524,"dataGaLocation":471},"/terms/","terms of use",{"text":526,"config":527},"Privacy statement",{"href":528,"dataGaName":529,"dataGaLocation":471},"/privacy/","privacy statement",{"text":531,"config":532},"Cookie preferences",{"dataGaName":533,"dataGaLocation":471,"id":534,"isOneTrustButton":30},"cookie preferences","ot-sdk-btn",{"title":94,"links":536,"subMenu":544},[537,540],{"text":23,"config":538},{"href":76,"dataGaName":539,"dataGaLocation":471},"devsecops platform",{"text":541,"config":542},"AI-Assisted Development",{"href":83,"dataGaName":543,"dataGaLocation":471},"ai-assisted development",[545],{"title":546,"links":547},"Topics",[548,553,558,563,568,571,576,581],{"text":549,"config":550},"CICD",{"href":551,"dataGaName":552,"dataGaLocation":471},"/topics/ci-cd/","cicd",{"text":554,"config":555},"GitOps",{"href":556,"dataGaName":557,"dataGaLocation":471},"/topics/gitops/","gitops",{"text":559,"config":560},"DevOps",{"href":561,"dataGaName":562,"dataGaLocation":471},"/topics/devops/","devops",{"text":564,"config":565},"Version Control",{"href":566,"dataGaName":567,"dataGaLocation":471},"/topics/version-control/","version control",{"text":26,"config":569},{"href":570,"dataGaName":41,"dataGaLocation":471},"/topics/devsecops/",{"text":572,"config":573},"Cloud Native",{"href":574,"dataGaName":575,"dataGaLocation":471},"/topics/cloud-native/","cloud native",{"text":577,"config":578},"AI for Coding",{"href":579,"dataGaName":580,"dataGaLocation":471},"/topics/devops/ai-for-coding/","ai for coding",{"text":582,"config":583},"Agentic AI",{"href":584,"dataGaName":585,"dataGaLocation":471},"/topics/agentic-ai/","agentic ai",{"title":587,"links":588},"Solutions",[589,591,593,598,602,605,609,612,614,617,620,625],{"text":136,"config":590},{"href":131,"dataGaName":136,"dataGaLocation":471},{"text":125,"config":592},{"href":108,"dataGaName":109,"dataGaLocation":471},{"text":594,"config":595},"Agile development",{"href":596,"dataGaName":597,"dataGaLocation":471},"/solutions/agile-delivery/","agile delivery",{"text":599,"config":600},"SCM",{"href":121,"dataGaName":601,"dataGaLocation":471},"source code management",{"text":549,"config":603},{"href":114,"dataGaName":604,"dataGaLocation":471},"continuous integration & delivery",{"text":606,"config":607},"Value stream management",{"href":164,"dataGaName":608,"dataGaLocation":471},"value stream management",{"text":554,"config":610},{"href":611,"dataGaName":557,"dataGaLocation":471},"/solutions/gitops/",{"text":174,"config":613},{"href":176,"dataGaName":177,"dataGaLocation":471},{"text":615,"config":616},"Small business",{"href":181,"dataGaName":182,"dataGaLocation":471},{"text":618,"config":619},"Public sector",{"href":186,"dataGaName":187,"dataGaLocation":471},{"text":621,"config":622},"Education",{"href":623,"dataGaName":624,"dataGaLocation":471},"/solutions/education/","education",{"text":626,"config":627},"Financial services",{"href":628,"dataGaName":629,"dataGaLocation":471},"/solutions/finance/","financial services",{"title":194,"links":631},[632,634,636,638,641,643,645,647,649,651,653,655],{"text":206,"config":633},{"href":208,"dataGaName":209,"dataGaLocation":471},{"text":211,"config":635},{"href":213,"dataGaName":214,"dataGaLocation":471},{"text":216,"config":637},{"href":218,"dataGaName":219,"dataGaLocation":471},{"text":221,"config":639},{"href":223,"dataGaName":640,"dataGaLocation":471},"docs",{"text":244,"config":642},{"href":246,"dataGaName":247,"dataGaLocation":471},{"text":239,"config":644},{"href":241,"dataGaName":242,"dataGaLocation":471},{"text":249,"config":646},{"href":251,"dataGaName":252,"dataGaLocation":471},{"text":257,"config":648},{"href":259,"dataGaName":260,"dataGaLocation":471},{"text":262,"config":650},{"href":264,"dataGaName":265,"dataGaLocation":471},{"text":267,"config":652},{"href":269,"dataGaName":270,"dataGaLocation":471},{"text":272,"config":654},{"href":274,"dataGaName":275,"dataGaLocation":471},{"text":277,"config":656},{"href":279,"dataGaName":280,"dataGaLocation":471},{"title":295,"links":658},[659,661,663,665,667,669,671,675,680,682,684,686],{"text":302,"config":660},{"href":304,"dataGaName":297,"dataGaLocation":471},{"text":307,"config":662},{"href":309,"dataGaName":310,"dataGaLocation":471},{"text":315,"config":664},{"href":317,"dataGaName":318,"dataGaLocation":471},{"text":320,"config":666},{"href":322,"dataGaName":323,"dataGaLocation":471},{"text":325,"config":668},{"href":327,"dataGaName":328,"dataGaLocation":471},{"text":330,"config":670},{"href":332,"dataGaName":333,"dataGaLocation":471},{"text":672,"config":673},"Sustainability",{"href":674,"dataGaName":672,"dataGaLocation":471},"/sustainability/",{"text":676,"config":677},"Diversity, inclusion and belonging (DIB)",{"href":678,"dataGaName":679,"dataGaLocation":471},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":335,"config":681},{"href":337,"dataGaName":338,"dataGaLocation":471},{"text":345,"config":683},{"href":347,"dataGaName":348,"dataGaLocation":471},{"text":350,"config":685},{"href":352,"dataGaName":353,"dataGaLocation":471},{"text":687,"config":688},"Modern Slavery Transparency Statement",{"href":689,"dataGaName":690,"dataGaLocation":471},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":692},[693,696,699],{"text":694,"config":695},"Terms",{"href":523,"dataGaName":524,"dataGaLocation":471},{"text":697,"config":698},"Cookies",{"dataGaName":533,"dataGaLocation":471,"id":534,"isOneTrustButton":30},{"text":700,"config":701},"Privacy",{"href":528,"dataGaName":529,"dataGaLocation":471},[703],{"id":704,"title":18,"body":8,"config":705,"content":707,"description":8,"extension":28,"meta":711,"navigation":30,"path":712,"seo":713,"stem":714,"__hash__":715},"blogAuthors/en-us/blog/authors/fatima-sarah-khalid.yml",{"template":706},"BlogAuthor",{"name":18,"config":708},{"headshot":709,"ctfId":710},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663337/Blog/Author%20Headshots/sugaroverflow-headshot.jpg","sugaroverflow",{},"/en-us/blog/authors/fatima-sarah-khalid",{},"en-us/blog/authors/fatima-sarah-khalid","GpfAGDKB-pWdwSjPp8CXd-29am9proj8tK7mm1IN_rs",[717,730,743],{"content":718,"config":728},{"heroImage":719,"title":720,"description":721,"authors":722,"date":724,"category":9,"tags":725,"body":727},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643639/sapu29gmlgtwvhggmj6k.png","Extend GitLab Duo Agent Platform: Connect any tool with MCP","Learn how to connect external tools to GitLab Duo Agent Platform using MCP. Step-by-step setup with three practical workflow demos.",[723],"Albert Rabassa","2026-03-05",[9,726,27],"product","Managing software development often means juggling multiple tools: tracking issues in Jira, writing code in your IDE, and collaborating through GitLab. Context switching between these platforms disrupts focus and slows down delivery.\n\nWith GitLab Duo Agent Platform's [MCP](https://about.gitlab.com/topics/ai/model-context-protocol/) support, you can now connect Jira or any tool that supports MCP directly to your AI-powered development environment. Query issues, update tickets, and sync your workflow — all through natural language, without ever leaving your IDE.\n\n## What you'll learn\n\nIn this tutorial, we'll walk you through:\n\n* **Setting up the Jira/Atlassian OAuth application** for secure authentication\n* **Configuring GitLab Duo Agent Platform** as an MCP client\n* **Three practical use cases** demonstrating real-world workflows\n\n## Prerequisites\n\nBefore getting started, ensure you have the following:\n\n| Requirement | Details |\n| ---- | ----- |\n| **GitLab instance** | GitLab 18.8+ with Duo Agent Platform enabled |\n| **Jira account** | Jira Cloud instance with admin access to create OAuth applications |\n| **IDE** | Visual Studio Code with GitLab Workflow extension installed |\n| **MCP support** | MCP support enabled in GitLab |\n\n\n## Understanding the architecture\n\nGitLab Duo Agent Platform acts as an **MCP client**, connecting to the Atlassian MCP server to access your Jira project management data. Atlassian  MCP server handles authentication, translates natural language requests into API calls, and returns structured data back to GitLab Duo Agent Platform — all while maintaining security and audit controls.\n\n## Part 1: Configure Jira OAuth application\n\nTo securely connect GitLab Duo Agent Platform to your Jira instance, you'll need to create an OAuth 2.0 application in the Atlassian Developer Console. This grants to GitLab the MCP server authorized access to your Jira data.\n\n### Setup steps\n\nIf you prefer to configure manually, follow these steps:\n\n1. **Navigate to the Atlassian Developer Console**\n\n   * Go to [developer.atlassian.com/console/myapps](https://developer.atlassian.com/console/myapps)\n\n   * Sign in with your Atlassian account\n\n2. **Create a new OAuth 2.0 app**\n\n   * Click **Create** → **OAuth 2.0 integration**\n\n   * Enter a name (e.g., \"gitlab-dap-mcp\")\n\n   * Accept the terms and click **Create**\n\n3. **Configure permissions**\n\n   * Navigate to **Permissions** in the left sidebar.\n\n   * Add **Jira API** and configure the following scopes:\n\n     * `read:jira-work` — Read issues, projects, and boards\n\n     * `write:jira-work` — Create and update issues\n\n     * `read:jira-user` — Read user information\n\n4. **Set up authorization**\n\n   * Go to **Authorization** in the left sidebar\n\n   * Add a callback URL for your environment (`https://gitlab.com/oauth/callback`)\n\n   * Save your changes\n\n5. **Retrieve credentials**\n\n   * Navigate to **Settings**\n\n   * Copy your **Client ID** and **Client Secret**\n\n   * Store these securely — you'll need them for the MCP configuration\n\n\n### Interactive walkthrough: Jira OAuth setup\n\nClick on the image below to get started.\n\n\n[![Jira OAuth setup tour](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772644850/wnzfoq43nkkfmgdqldmr.png)](https://gitlab.navattic.com/jira-oauth-setup)\n\n\n## Part 2: Configure GitLab Duo Agent Platform MCP client\n\nWith your OAuth credentials ready, you can now configure GitLab Duo Agent Platform to connect to the Atlassian MCP server.\n\n### Create your MCP configuration file\n\nCreate the MCP configuration file in your GitLab project at `.gitlab/duo/mcp.json`:\n\n\n```json\n{\n  \"mcpServers\": {\n    \"atlassian\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.atlassian.com/v1/mcp\",\n      \"auth\": {\n        \"type\": \"oauth2\",\n        \"clientId\": \"YOUR_CLIENT_ID\",\n        \"clientSecret\": \"YOUR_CLIENT_SECRET\",\n        \"authorizationUrl\": \"https://auth.atlassian.com/oauth/authorize\",\n        \"tokenUrl\": \"https://auth.atlassian.com/oauth/token\"\n      },\n      \"approvedTools\": true\n    }\n  }\n}\n```\n\nReplace `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET` with the credentials you generated in Part 1.\n\n### Enable MCP in GitLab\n\n1. Navigate to your **Group Settings** → **GitLab Duo** → **Configuration**\n2. Make sure “Allow external MCP tools” is checked\n\n### Verify the connection\n\nOpen your project in VS Code and ask in GitLab Duo Agent Platform chat:\n\n```text\nWhat MCP tools do you have access to?\n```\n\nThen\n\n```text\nTest the MCP JIRA configuration in this project\n```\n\nAt this point you'll be redirected from the IDE to the MCP Atlassian website to approve access:\n\n![Redirect to MCP Atlassian website](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643461/z5acqjgguh0damnnde9g.png \"Redirect to MCP Atlassian website\")\n\n\u003Cbr>\u003C/br>\n\n![Approve access](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643461/rwowamm8nsubhpixtn3i.png \"Approve access\")\n\n\u003Cbr>\u003C/br>\n\n![Select your JIRA instance and approve](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643461/chuzqd0jeptfwvoj7wjr.png \"Select your JIRA instance and approve\")\n\n\u003Cbr>\u003C/br>\n\n![Success!](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643462/bsgti5iste2bzck19o5y.png \"Success!\")\n\n\u003Cbr>\u003C/br>\n\n### Verify with the MCP Dashboard\n\nGitLab also provides a built-in **MCP Dashboard** directly in your IDE for this.\n\nIn VS Code or VSCodium, open the Command Palette (`Cmd+Shift+P` on macOS, `Ctrl+Shift+P` on Windows/Linux) and search for **\"GitLab: Show MCP Dashboard\"**. The dashboard opens in a new editor tab and gives you:\n\n* **Connection status** for each configured MCP server\n* **Available tools** exposed by the server (e.g., `jira_get_issue`, `jira_create_issue`)\n* **Server logs** so you can see exactly which tools are being called in real time\n\n![MCP servers dashboard and status](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643462/mmvdfchucacsydivowvn.png \"MCP servers dashboard and status\")\n\n\u003Cbr>\u003C/br>\n\n![Server details and permissions](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643462/tcocgdvovp2dl42pvfn8.png \"Server details and permissions\")\n\n\u003Cbr>\u003C/br>\n\n\n![MCP Server logs](https://res.cloudinary.com/about-gitlab-com/image/upload/v1772643466/mougvqqk1bozchaufsci.png \"MCP Server logs\")\n\n\u003Cbr>\u003C/br>\n\n### Interactive walkthrough: Testing MCP\n\n\u003Ciframe src=\"https://player.vimeo.com/video/1170005495?badge=0&amp;autopause=0&amp; player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Testing MCP\">\u003C/iframe>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n## Part 3: Use cases in action\n\nNow that your integration is configured, let's explore three practical workflows that demonstrate the power of connecting Jira to GitLab Duo Agent Platform.\n\n### Planning assistant\n\n**Scenario:** You're preparing for sprint planning and need to quickly assess the backlog, understand priorities, and identify blockers.\n\nThis demo shows you how to:\n\n* Query the backlog\n* Identify unassigned high-priority issues\n* Get AI-powered sprint recommendations\n\n#### Example prompts\n\nTry these prompts in GitLab Duo Agent Platform Chat:\n\n```text\nList all the unassigned issues in JIRA for project GITLAB\n```\n\n```text\nSuggest the two top issues to prioritize and summarize them. Assign them to me.\n```\n\n### Interactive walkthrough: Project planning\n\n\u003Ciframe src=\"https://player.vimeo.com/video/1170005462?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Project Planning\">\u003C/iframe>\u003Cscript src=\"https://player.vimeo.com/api/player. js\">\u003C/script>\n\n### Issue triage and creation from code\n\n**Scenario:** While reviewing code, you discover a bug and want to create a Jira issue with relevant context — without leaving your IDE.\n\nThis demo walks you through:\n\n* Identifying a bug while coding\n* Creating a detailed Jira issue via natural language\n* Auto-populating issue fields with code context\n* Linking the issue to your current branch\n\n#### Example prompts\n\n```text\nSearch in JIRA for a bug related to: Null pointer exception in PaymentService.processRefund().\nIf it does not exist create it with all the context needed from the code. Find possible blockers that this bug may cause.\n```\n\n```text\nCreate a new branch called issue-gitlab-18, checkout, and link it to the issue we just created. Assign the JIRA issue to me and mark it as in-progress.\n```\n\n### Interactive walkthrough: Bug review and task automation\n\n\u003Ciframe src=\"https://player.vimeo.com/video/1170005368?badge=0&amp;autopause=0&amp; player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Bug Review\">\u003C/iframe>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n### Cross-system incident investigation\n\n**Scenario:** A production incident occurs, and you need to correlate information from Jira (incident ticket), GitLab Project Management, your codebase, and merge requests to identify the root cause.\n\nThis demo demonstrates:\n\n* Fetching incident details from Jira\n* Correlating with recent merge requests in GitLab\n* Identifying potentially related code changes\n* Generating an incident timeline\n* Design a remediation plan and create it as a work item in GitLab\n\n#### Example prompts\n\n```text\n\"We have a production incident INC-1 about checkout failures. Can you help me investigate with all available context?\"\n```\n\n```text\nCreate a timeline of events for incident INC-1 including related Jira issues and recent deployments\n```\n\n```text\nPropose a remediation plan\n```\n\n### Interactive walkthrough: Cross-system troubleshooting and remediation\n\n\u003Ciframe src=\"https://player.vimeo.com/video/1170005413?badge=0&amp;autopause=0&amp; player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Cross System Investigation\">\u003C/iframe>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n## Troubleshooting\n\nThese are some common setup issues and quick fixes:\n\n| Issue | Solution |\n| ----- | ----- |\n| \"MCP server not found\" | Verify the `mcp.json` file is in the correct location and properly formatted |\n| \"Authentication failed\" | Re-check your OAuth credentials and ensure scopes are correctly configured in Atlassian |\n| \"No Jira tools available\" | Restart VS Code after updating `mcp.json` and ensure MCP is enabled in GitLab |\n| \"Connection timeout\" | Check your network connectivity to `mcp.atlassian.com` |\n\n\u003Cbr/> For detailed troubleshooting, see the [GitLab MCP clients documentation](https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_clients/).\n\n\n## Security considerations\n\nWhen integrating Jira with GitLab Duo Agent Platform:\n\n* **OAuth tokens** — Make sure credentials remain secure\n* **Principle of least privilege** — Only grant the minimum required Jira scopes\n* **Token rotation** — Regularly rotate your OAuth credentials as part of security hygiene\n\n\n## Summary\n\nConnecting GitLab Duo Agent Platform to different tools through MCP transforms how you interact with your development lifecycle. In this article, you have learned how to:\n\n* **Query issues naturally** — Ask questions about your backlog, sprints, and incidents in natural language.\n* **Create and update issues on all your DevSecOps environment** — File bugs and update tickets without leaving your IDE.\n* **Correlate across systems** — Combine Jira data with GitLab project management, merge requests, and pipelines for complete visibility.\n* **Reduce context switching** — Keep your focus on code while staying connected to project management.\n\nThis integration exemplifies the power of MCP: standardized, secure access to your tools through AI, enabling developers to work more efficiently without sacrificing governance or security.\n\n\n## Read more\n\n* [GitLab Duo Agent Platform adds support for Model Context Protocol](https://about.gitlab.com/blog/duo-agent-platform-with-mcp/)\n\n* [What is Model Context Protocol?](https://about.gitlab.com/topics/ai/model-context-protocol/)\n\n* [Agentic AI guides and resources](https://about.gitlab.com/blog/agentic-ai-guides-and-resources/)\n\n* [GitLab MCP clients documentation](https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_clients/)\n\n* [Get started with GitLab Duo Agent Platform: The complete guide](https://about.gitlab.com/blog/gitlab-duo-agent-platform-complete-getting-started-guide/)",{"featured":12,"template":13,"slug":729},"extend-gitlab-duo-agent-platform-connect-any-tool-with-mcp",{"content":731,"config":741},{"title":732,"description":733,"authors":734,"heroImage":736,"date":737,"body":738,"category":9,"tags":739},"10 AI prompts to speed your team’s software delivery","Eliminate review backlogs, security delays, and coordination overhead with ready-to-use AI prompts covering every stage of the software lifecycle.",[735],"Chandler Gibbons","https://res.cloudinary.com/about-gitlab-com/image/upload/v1772632341/duj8vaznbhtyxxhodb17.png","2026-03-04","AI-assisted coding tools are helping developers generate code faster than ever. So why aren’t teams _shipping_ faster?\n\nBecause coding is only 20% of the software delivery lifecycle, the remaining 80% becomes the bottleneck: code review backlogs grow, security scanning can’t keep pace, documentation falls behind, and manual coordination overhead increases.\n\nThe good news is that the same AI capabilities that accelerate individual coding can eliminate these team-level delays. You just need to apply AI across your entire software lifecycle, not only during the coding phase.\n\nBelow are 10 ready-to-use prompts from the [GitLab Duo Agent Platform Prompt Library](https://about.gitlab.com/gitlab-duo/prompt-library/) that help teams overcome common obstacles to faster software delivery. Each prompt addresses a specific slowdown that emerges when individual productivity increases without corresponding improvements in team processes.\n\n## How do you move code review from bottleneck to accelerator?\nDevelopers generate merge requests faster with AI assistance, but human reviewers can quickly become overwhelmed as code review cycles stretch from hours to days. AI can handle routine review tasks, freeing reviewers to focus on architecture and business logic instead of catching basic logical errors and API contract violations.\n\n### Review MR for logical errors\n**Complexity**: Beginner\n\n**Category**: Code Review\n\n**Prompt from library**:\n\n\n```text\nReview this MR for logical errors, edge cases, and potential bugs: [MR URL or paste code]\n```\n\n**Why it helps**: Automated linters catch syntax issues, but logical errors require understanding intent. This prompt catches bugs before human reviewers even look at the code, reducing review cycles from multiple rounds to often just one approval.\n\n### Identify breaking changes in MR\n**Complexity**: Beginner\n\n**Category**: Code Review\n\n**Prompt from library**:\n\n\n```text\nDoes this MR introduce any breaking changes?\n\nChanges:\n[PASTE CODE DIFF]\n\nCheck for:\n1. API signature changes\n2. Removed or renamed public methods\n3. Changed return types\n4. Modified database schemas\n5. Breaking configuration changes\n```\n\n**Why it helps**: Breaking changes discovered during deployment can cause rollbacks and incidents. This prompt shifts that discovery left to the MR stage, when fixes are faster and less expensive.\n\n## How can you shift security left without slowing down?\nSecurity scans generate hundreds of findings. Security teams manually triage each one while developers wait for approval to deploy. Most findings are false positives or low-risk issues, but identifying the real threats requires expertise and time. AI can prioritize findings by actual exploitability and auto-remediate common vulnerabilities, allowing security teams to focus on the threats that matter.\n\n### Analyze security scan results\n**Complexity**: Intermediate\n\n**Category**: Security\n\n**Agent**: Duo Security Analyst\n\n**Prompt from library**:\n\n\n```text\n@security_analyst Analyze these security scan results:\n\n[PASTE SCAN OUTPUT]\n\nFor each finding:\n1. Assess real risk vs false positive\n2. Explain the vulnerability\n3. Suggest remediation\n4. Prioritize by severity\n```\n\n**Why it helps**: Most security scan findings are false positives or low-risk issues. This prompt helps security teams focus on the findings that actually matter, reducing remediation time from weeks to days.\n\n### Review code for security issues\n**Complexity**: Intermediate\n\n**Category**: Security\n\n**Agent**: Duo Security Analyst\n\n**Prompt from library**:\n\n```text\n@security_analyst Review this code for security issues:\n\n[PASTE CODE]\n\nCheck for:\n1. Injection vulnerabilities\n2. Authentication/authorization flaws\n3. Data exposure risks\n4. Insecure dependencies\n5. Cryptographic issues\n```\n\n**Why it helps**: Traditional security reviews happen after code is written. This prompt enables developers to find and fix security issues before creating an MR, eliminating the back and forth that delays deployments.\n\n## How do you keep documentation current as code changes?\nCode changes faster than documentation. Onboarding new developers takes weeks because docs are outdated or missing. Teams know documentation is important, but it always gets deferred when deadlines approach. Automating documentation generation and updates as part of your standard workflow ensures docs stay current without adding manual work.\n\n### Generate release notes from MRs\n**Complexity**: Beginner\n\n**Category**: Documentation\n\n**Prompt from library**:\n\n```text\nGenerate release notes for these merged MRs:\n[LIST MR URLs or paste titles]\n\nGroup by:\n1. New features\n2. Bug fixes\n3. Performance improvements\n4. Breaking changes\n5. Deprecations\n```\n\n**Why it helps**: Manual release note compilation takes hours and often includes errors or omissions. Automated generation ensures every release has comprehensive notes without adding work to your release process.\n\n### Update documentation after code changes\n**Complexity**: Beginner\n\n**Category**: Documentation\n\n**Prompt from library**:\n\n```text\nI changed this code:\n\n[PASTE CODE CHANGES]\n\nWhat documentation needs updating? Check:\n1. README files\n2. API documentation\n3. Architecture diagrams\n4. Onboarding guides\n```\n\n**Why it helps**: Documentation drift happens because teams forget which docs need updates after code changes. This prompt makes documentation maintenance part of your development workflow, not a separate task that gets deferred.\n\n## How do you break down planning complexity?\nLarge features get stuck in planning. Teams spend weeks in meetings trying to scope work and identify dependencies. The complexity feels overwhelming, and it's hard to know where to start. AI can systematically decompose complex work into concrete, implementable tasks with clear dependencies and acceptance criteria, transforming weeks of planning into focused implementation.\n\n### Break down epic into issues\n**Complexity**: Intermediate\n\n**Category**: Documentation\n\n**Agent**: Duo Planner\n\n**Prompt from library**:\n\n```text\nBreak down this epic into implementable issues:\n\n[EPIC DESCRIPTION]\n\nConsider:\n1. Technical dependencies\n2. Reasonable issue sizes\n3. Clear acceptance criteria\n4. Logical implementation order\n```\n\n**Why it helps**: This prompt transforms a week of planning meetings into 30 minutes of AI-assisted decomposition followed by team review. Teams start implementation sooner with clearer direction.\n\n## How can you expand test coverage without expanding effort?\nDevelopers are writing code faster, but if testing doesn't keep pace, test coverage decreases and bugs slip through. Writing comprehensive tests manually is time-consuming, and developers often miss edge cases under deadline pressure. Generating tests automatically means developers can review and refine rather than write from scratch, maintaining quality without sacrificing velocity.\n\n### Generate unit tests\n**Complexity**: Beginner\n\n**Category**: Testing\n\n**Prompt from library**:\n\n```text\nGenerate unit tests for this function:\n\n[PASTE FUNCTION]\n\nInclude tests for:\n1. Happy path\n2. Edge cases\n3. Error conditions\n4. Boundary values\n5. Invalid inputs\n```\n\n**Why it helps**: Writing tests manually is time consuming, and developers often miss edge cases. This prompt generates thorough test suites in seconds, which developers can review and adjust rather than write from scratch.\n\n### Review test coverage gaps\n**Complexity**: Beginner\n\n**Category**: Testing\n\n**Prompt from library**:\n\n```text\nAnalyze test coverage for [MODULE/COMPONENT]:\n\nCurrent coverage: [PERCENTAGE]\n\nIdentify:\n1. Untested functions/methods\n2. Uncovered edge cases\n3. Missing error scenario tests\n4. Integration points without tests\n5. Priority areas to test next\n```\n\n**Why it helps**: This prompt reveals blind spots in your test suite before they cause production incidents. Teams can systematically improve coverage where it matters most.\n\n## How do you reduce mean time to resolution when debugging?\nProduction incidents take hours to diagnose. Developers wade through logs and stack traces while customers experience downtime. Every minute of debugging is a minute of lost productivity and potential revenue. AI can accelerate root cause analysis by parsing complex error messages and suggesting specific fixes, cutting diagnostic time from hours to minutes.\n\n### Debug failing pipeline\n**Complexity**: Beginner\n\n**Category**: Debugging\n\n**Prompt from library**:\n\n```text\nThis pipeline is failing:\n\nJob: [JOB NAME]\nStage: [STAGE]\nError: [PASTE ERROR MESSAGE/LOG]\n\nHelp me:\n1. Identify the root cause\n2. Suggest a fix\n3. Explain why it started failing\n4. Prevent similar issues\n```\n\n**Why it helps**: CI/CD failures block entire teams. This prompt diagnoses failures in seconds instead of the 15-30 minutes developers typically spend investigating, keeping deployment velocity high.\n\n## Moving from individual gains to team acceleration\nThese prompts represent a shift in how teams apply AI to software delivery. Rather than focusing solely on individual developer productivity, they address the coordination, quality, and knowledge-sharing challenges that actually constrain team velocity.\n\nThe [complete prompt library](https://about.gitlab.com/gitlab-duo/prompt-library/) contains more than 100 prompts across all stages of the software lifecycle: planning, development, security, testing, deployment, and operations. Each prompt is tagged by complexity level (Beginner, Intermediate, Advanced) and categorized by use case, making it easy to find the right starting point for your team.\n\nStart with prompts tagged “Beginner” that address your team’s most pressing obstacles. As your team builds confidence, explore intermediate and advanced prompts that enable more sophisticated workflows. The goal is not just faster coding — it's faster, safer, higher-quality software delivery from planning through production.",[24,740],"DevOps platform",{"featured":12,"template":13,"slug":742},"10-ai-prompts-to-speed-your-teams-software-delivery",{"content":744,"config":754},{"title":745,"description":746,"heroImage":747,"authors":748,"date":750,"body":751,"category":9,"tags":752},"AI can detect vulnerabilities, but who governs risk?","AI-assisted vulnerability detection is developing fast, but the harder challenges of enforcement, governance, and supply chain security require a holistic platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1772195014/ooezwusxjl1f7ijfmbvj.png",[749],"Omer Azaria","2026-02-27","Anthropic recently announced Claude Code Security, an AI system that detects vulnerabilities and proposes fixes. The market reacted immediately, with security stocks dipping as investors questioned whether AI might replace traditional AppSec tools. The question on everyone's mind: If AI can write code and secure it, is application security about to become obsolete?\n\nIf security only meant scanning code, the answer might be yes. But enterprise security has never been about detection alone.\n\nOrganizations are not asking whether AI can find vulnerabilities. They are asking three much harder questions: \n\n* Is what we are about to ship safe?  \n* Has our risk posture changed as environments evolve and dependencies, third-party services, tools, and infrastructure continuously shift?  \n* How do we govern a codebase that is increasingly assembled by AI and third-party sources, and that we are still accountable for? \n\nThose questions require a platform answer: Detection surfaces risk, but governance determines what happens next. \n\n[GitLab](https://about.gitlab.com/) is the orchestration layer built to govern the software lifecycle end-to-end. It gives teams the enforcement, visibility, and auditability they need to keep pace with the speed of AI-assisted development.\n\n## Trusting AI requires governing risk\n\nAI systems are rapidly getting better at identifying vulnerabilities and suggesting fixes. This is a meaningful and welcome advancement, but analysis is not accountability.\n\nAI cannot enforce company policy or define acceptable risk on its own. Humans must set the boundaries, policies, and guardrails that agents operate within, establishing separation of duties, ensuring audit trails, and maintaining consistent controls across thousands of repositories and teams. Trust in agents comes not from autonomy alone, but from clearly defined governance set by people. \n\nIn an [agentic world](https://about.gitlab.com/topics/agentic-ai/), where software is increasingly written and modified by autonomous systems, governance becomes more important, not less. The more autonomy organizations grant to AI, the stronger the governance must be.\n\nGovernance is not friction. It is the foundation that makes AI-assisted development trustworthy at scale.\n\n## LLMs see code, but platforms see context\n\nA large language model ([LLM](https://about.gitlab.com/blog/what-is-a-large-language-model-llm/)) evaluates code in isolation. An enterprise application security platform understands context. This difference matters because risk decisions are contextual:\n\n* Who authored the change?  \n* How critical is the application to the business?  \n* How does it interact with infrastructure and dependencies?  \n* Does the vulnerability exist in code that is actually reachable in production, or is it buried in a dependency that never executes?  \n* Is it actually exploitable in production, given how the application runs, its APIs, and the environment around it?\n\nSecurity decisions depend on this context. Without it, detection produces noisy alerts that slow down development rather than reducing risk. With it, organizations can triage quickly and manage risk effectively. Context evolves continuously as software changes, which means governance cannot be a one-time decision. \n\n## Static scans can’t keep up with dynamic risk\n\nSoftware risk is dynamic. Dependencies change, environments evolve, and systems interact in ways no single analysis can fully predict. A clean scan at one moment does not guarantee safety at release.\n\nEnterprise security depends on continuous assurance: controls embedded directly into development workflows that evaluate risk as software is built, tested, and deployed.\n\nDetection provides insight. Governance provides trust. Continuous governance is what allows organizations to ship safely at scale.\n\n## Governing the agentic future\n\nAI is reshaping how software is created. The question is no longer whether teams will use AI, but how safely they can scale it.\n\nSoftware today is assembled as much as it is written, from AI-generated code, open-source libraries, and third-party dependencies that span thousands of projects. Governing what ships across all of those sources is the hardest and most consequential part of application security, and it is the part that no developer-side tool is built to address. \n\nAs an intelligent orchestration platform, GitLab is built to address this problem. GitLab Ultimate embeds governance, policy enforcement, security scanning, and auditability directly into the workflows where software is planned, built, and shipped, so security teams can govern at the speed of AI. \n\nAI will accelerate development dramatically. The organizations that benefit most from AI will not be those with the smartest assistants alone, but those that build trust through strong governance.\n\n> To learn how GitLab helps organizations [govern and ship AI-generated code](https://about.gitlab.com/solutions/software-compliance/?utm_medium=blog&utm_campaign=eg_global_x_x_security_en_) safely, [talk to our team today](https://about.gitlab.com/sales/?utm_medium=blog&utm_campaign=eg_global_x_x_security_en_)\n\n\n ## Related reading\n\n - [Integrating AI with DevOps for enhanced security](https://about.gitlab.com/topics/devops/ai-enhanced-security/)\n - [The GitLab AI Security Framework for security leaders](https://about.gitlab.com/blog/the-gitlab-ai-security-framework-for-security-leaders/)\n - [Improve AI security in GitLab with composite identities](https://about.gitlab.com/blog/improve-ai-security-in-gitlab-with-composite-identities/)",[24,753],"security",{"featured":30,"template":13,"slug":755},"ai-can-detect-vulnerabilities-but-who-governs-risk",{"promotions":757},[758,771,782],{"id":759,"categories":760,"header":761,"text":762,"button":763,"image":768},"ai-modernization",[9],"Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":764,"config":765},"Get your AI maturity score",{"href":766,"dataGaName":767,"dataGaLocation":247},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":769},{"src":770},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":772,"categories":773,"header":774,"text":762,"button":775,"image":779},"devops-modernization",[726,41],"Are you just managing tools or shipping innovation?",{"text":776,"config":777},"Get your DevOps maturity score",{"href":778,"dataGaName":767,"dataGaLocation":247},"/assessments/devops-modernization-assessment/",{"config":780},{"src":781},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":783,"categories":784,"header":785,"text":762,"button":786,"image":790},"security-modernization",[753],"Are you trading speed for security?",{"text":787,"config":788},"Get your security maturity score",{"href":789,"dataGaName":767,"dataGaLocation":247},"/assessments/security-modernization-assessment/",{"config":791},{"src":792},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"header":794,"blurb":795,"button":796,"secondaryButton":801},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":797,"config":798},"Get your free trial",{"href":799,"dataGaName":54,"dataGaLocation":800},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":509,"config":802},{"href":58,"dataGaName":59,"dataGaLocation":800},1777309982383]