{"id":2222,"date":"2025-07-09T18:16:41","date_gmt":"2025-07-09T18:16:41","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/07\/09\/how-the-net-maui-team-uses-github-copilot-for-productivity\/"},"modified":"2025-07-09T18:16:41","modified_gmt":"2025-07-09T18:16:41","slug":"how-the-net-maui-team-uses-github-copilot-for-productivity","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/07\/09\/how-the-net-maui-team-uses-github-copilot-for-productivity\/","title":{"rendered":"How the .NET MAUI Team uses GitHub Copilot for Productivity"},"content":{"rendered":"<p>Around the time of Microsoft Build 2025, the new <a href=\"https:\/\/github.blog\/news-insights\/product-news\/github-copilot-meet-the-new-coding-agent\/\">GitHub Copilot<br \/>\nCoding Agent<\/a> was unveiled and made widely available across<br \/>\nGitHub. With AI evolving at a dizzying pace in recent months, we<br \/>\nimagined a \u201cdream scenario\u201d:<\/p>\n<p>A GitHub issue is filed.<br \/>\nThe problem looks to have a straightforward solution.<br \/>\nA team member assigns the issue to Copilot, giving it a few tips.<br \/>\nCopilot generates a pull request with the fix (and tests).<br \/>\nCI runs, tests pass, and the pull request is merged!<\/p>\n<p>This would dramatically reduce time and effort, freeing <em>human<\/em><br \/>\ndevelopers to focus on higher-value, complex problems\u2013while Copilot<br \/>\ntakes care of the repetitive work.<\/p>\n<p>But would this dream be a reality? In this post, we aim to share a<br \/>\nbalanced perspective: highlighting both where Copilot has been<br \/>\ngenuinely helpful, and when it completely missed the mark.<\/p>\n<p>In many ways, it already is. The .NET MAUI team has been actively<br \/>\nusing Copilot to boost our productivity, and we\u2019re excited to share<br \/>\nsome practical tips for getting the most out of it.<\/p>\n<p>At the time of writing, Copilot has risen to be the #64 contributor all time in<br \/>\ndotnet\/maui, which we expect to grow in the coming months:<\/p>\n\n<h2>Step 1: .github\/copilot-instructions.md<\/h2>\n<p>To start with the basics, we provide GitHub Copilot with some general context and guidance for our repository by including a <a href=\"https:\/\/docs.github.com\/en\/copilot\/customizing-copilot\/adding-repository-custom-instructions-for-github-copilot\">copilot-instructions.md<\/a> file. By convention this file should be kept in the .github folder at the root of your repository or workspace. This works both locally when using Copilot in Visual Studio or VS Code and when using the GitHub Copilot Coding Agent on GitHub.<\/p>\n<p>The types of useful instructions we keep in this file include:<\/p>\n<p><strong>Project Context<\/strong>: What <em>is<\/em> this repo? Provide an overview of the<br \/>\nproject and relevant background information.<br \/>\n<strong>Repository Structure<\/strong>: Describe the structure of the repository,<br \/>\nwhat types of files go where, how to write tests, etc.<br \/>\n<strong>Coding Standards<\/strong>: If you are using non-default code formatting,<br \/>\ngive specific examples of how you want your code to look.<\/p>\n<p>A great way to start is to simply ask the Copilot Coding Agent to<br \/>\ngenerate this file for you.<\/p>\n<p>An example GitHub issue would be:<\/p>\n<p>Go through this repo, review structure of project, source code, etc.<\/p>\n<p>Additional docs to review about the product: https:\/\/learn.microsoft.com\/dotnet\/maui<\/p>\n<p>Update `.github\/copilot-instructions.md` to make Copilot more helpful going forward.<\/p>\n<p>Include a note to update `copilot-instructions.md` with new instructions as the project evolves.<\/p>\n<p>See: https:\/\/docs.github.com\/en\/copilot\/customizing-copilot\/adding-repository-custom-instructions-for-github-copilot <\/p>\n<p>Assign to Copilot and see what it comes up with. You can review and<br \/>\nremove any instructions that are not relevant.<\/p>\n<p>See examples of copilot-instructions.md files on GitHub at:<\/p>\n<p><a href=\"https:\/\/github.com\/dotnet\/maui\/blob\/main\/.github\/copilot-instructions.md\">dotnet\/maui<\/a><br \/>\n<a href=\"https:\/\/github.com\/dotnet\/android\/blob\/main\/.github\/copilot-instructions.md\">dotnet\/android<\/a><br \/>\n<a href=\"https:\/\/github.com\/dotnet\/macios\/blob\/main\/.github\/copilot-instructions.md\">dotnet\/macios<\/a><\/p>\n<h2>Step 2: Firewall Rules<\/h2>\n<p>When the GitHub Copilot Coding Agent completes your first assigned issue, you may notice a<br \/>\nwarning on the pull request description, such as:<\/p>\n\n<p>This warning is actually a key security feature:<\/p>\n<p>Imagine you\u2019re working on a \u201ctop secret\u201d private repository.<\/p>\n<p>Copilot decides to make a web request to a public website to<br \/>\nretrieve some data.<\/p>\n<p>Copilot could have inadvertently leaked your private code to the<br \/>\npublic website!<\/p>\n<p>While this is less of a concern in public repositories, this could<br \/>\nstill happen with GitHub secrets or other credentials.<\/p>\n<p>If you want Copilot to be able to make web requests, you can review<br \/>\neach firewall warning and configure rules to allow specific domains.<\/p>\n<p>Go to the Settings &gt; Environments &gt; copilot page on your GitHub repository.<\/p>\n<p>Scroll to the bottom, Environment variables section.<\/p>\n<p>Add a new COPILOT_AGENT_FIREWALL_ALLOW_LIST variable with a<br \/>\ncomma-separated list of domains you want to allow.<\/p>\n<p>Some useful domains to allow include:<\/p>\n<p>learn.microsoft.com \u2013 for Microsoft and .NET documentation.<br \/>\nnuget.org \u2013 to add new NuGet packages.<br \/>\ndeveloper.apple.com \u2013 for iOS and Apple-specific documentation.<br \/>\ndeveloper.android.com \u2013 for Android-specific documentation.<\/p>\n<div class=\"alert alert-primary\">\n<p class=\"alert-divider\"><strong>Note<\/strong><\/p>\n<p>$COPILOT_AGENT_FIREWALL_ALLOW_LIST should not have a trailing comma. See <a href=\"https:\/\/github.com\/copilot-coding-agent\/user-feedback\/issues\/41\">copilot-coding-agent\/user-feedback#41<\/a> for more details.<\/p><\/div>\n<h2>Step 3: .github\/workflows\/copilot-setup-steps.yml<\/h2>\n<p>Building upon GitHub (a platform), the Copilot Coding Agent literally<br \/>\nruns within GitHub actions. You have complete control over the<br \/>\nenvironment in which it runs, giving you the ability to run steps<br \/>\nbefore the firewall restrictions are applied:<\/p>\n<p>Download and install additional tools or dependencies.<\/p>\n<p>Restore NuGet packages or other steps that require network access.<\/p>\n<p>Do an inital (working) build of the project.<\/p>\n<p>This way Copilot has a working source tree, can make changes, build<br \/>\nagain (incrementally), run tests, etc.<\/p>\n<p>As with the previous step, you can file a GitHub issue and let Copilot<br \/>\ngenerate the copilot-setup-steps.yml file. Here\u2019s an example:<\/p>\n<p># Setup copilot development environment <\/p>\n<p>Setup a `.github\/workflows\/copilot-setup-steps.yml` file, such as:<\/p>\n<p>name: &#8220;Copilot Setup Steps&#8221;<br \/>\non: workflow_dispatch<br \/>\njobs:<br \/>\n  copilot-setup-steps:<br \/>\n    runs-on: ubuntu-latest<br \/>\n    steps:<br \/>\n    &#8211; name: Checkout repository<br \/>\n      uses: actions\/checkout@v4<br \/>\n      with:<br \/>\n        submodules: recursive<br \/>\n    &#8211; name: Setup .NET<br \/>\n      uses: actions\/setup-dotnet@v4<br \/>\n      with:<br \/>\n        dotnet-version: &#8216;9.x&#8217;<br \/>\n    # TODO: Build the project<\/p>\n<p>See `.github\/DEVELOPMENT.md` for more details on how to build this project.<\/p>\n<p>See: https:\/\/docs.github.com\/en\/copilot\/customizing-copilot\/customizing-the-development-environment-for-copilot-coding-agent<\/p>\n<p>Note that Copilot currently only supports ubuntu-latest as its<br \/>\nruntime OS. If your project needs Windows or macOS builds, Copilot may<br \/>\nbe somewhat restricted in what it can do. See (or upvote!)<br \/>\n<a href=\"https:\/\/github.com\/copilot-coding-agent\/user-feedback\/issues\/40\">copilot-coding-agent\/user-feedback#40<\/a> for more details.<\/p>\n<p>One important detail: make sure that copilot-setup-steps.yml is<br \/>\nconfigured to <em>always<\/em> complete, even if your build fails. This is<br \/>\ndone using continue-on-error: true.<\/p>\n<p>&#8211; name: Run dotnet build<br \/>\n  id: copilot-build<br \/>\n  continue-on-error: true<br \/>\n  run: dotnet build -bl<br \/>\n&#8211; name: Upload logs<br \/>\n  uses: actions\/upload-artifact@v4<br \/>\n  if: steps.copilot-build.outcome == &#8216;failure&#8217;<br \/>\n  with:<br \/>\n    name: copilot-artifacts<br \/>\n    path: &#8216;**\/*.binlog&#8217;<\/p>\n<p>Copilot (or a human) might push a commit that breaks the build. If you<br \/>\nleave a comment like @copilot fix error XYZ, it needs to be able get<br \/>\npast its setup steps and actually fix the problem. Having a copy of<br \/>\nthe failed logs can also be useful for humans troubleshooting in the<br \/>\nfuture.<\/p>\n<h2>Step 4: Setup MCP Servers (Optional)<\/h2>\n<p>A Model Context Protocol (MCP) server provides \u201ctools\u201d that Copilot<br \/>\ncan draw from to accomplish specific goals. In our experience, the<br \/>\n<a href=\"https:\/\/github.com\/MicrosoftDocs\/mcp\">Microsoft Learn Docs MCP Server<\/a> is one of the most powerful<br \/>\ntools available. This gives Copilot important context on many topics<br \/>\nbefore modifying your code.<\/p>\n<p>To set this up, go to your repository Settings &gt; Copilot &gt; Coding Agent &gt; MCP Configuration:<\/p>\n<p>{<br \/>\n  &#8220;mcpServers&#8221;: {<br \/>\n    &#8220;microsoft-docs-mcp&#8221;: {<br \/>\n      &#8220;type&#8221;: &#8220;http&#8221;,<br \/>\n      &#8220;url&#8221;: &#8220;https:\/\/learn.microsoft.com\/api\/mcp&#8221;,<br \/>\n      &#8220;tools&#8221;: [ &#8220;*&#8221; ]<br \/>\n    }<br \/>\n  }<br \/>\n}<\/p>\n<p>It is also a good idea to add the following guidance at the top of<br \/>\ncopilot-instructions.md:<\/p>\n<p>## Development Guidelines<\/p>\n<p>**Always search Microsoft documentation (MS Learn) when working with .NET, Windows, or Microsoft features, or APIs.** Use the `microsoft_docs_search` tool to find the most current information about capabilities, best practices, and implementation patterns before making changes.<\/p>\n<div class=\"alert alert-primary\">\n<p class=\"alert-divider\"><strong>Security Note<\/strong><\/p>\n<p>Just like the firewall allow list, the MCP server configuration is a potential security risk. Be sure to review any MCP server\u2019s source code and\/or documentation to decide if it is safe to use.<\/p><\/div>\n<p>To setup GitHub Copilot Coding Agent end-to-end:<\/p>\n\n<p>Note that much of this is optional, but Copilot can complete tasks<br \/>\nfaster and more reliably with a complete setup.<\/p>\n<h2>Storytime: AI\u2019s Little White Lies<\/h2>\n<p>As a fun experiment, I used the Copilot Coding Agent to create a new<br \/>\n.NET MAUI app called <a href=\"https:\/\/github.com\/jonathanpeppers\/CatSwipe\">CatSwipe<\/a>. It displays cat images from<br \/>\nthecatapi.com, and lets you swipe left\/no or right\/yes (similar to a<br \/>\npopular a dating app).<\/p>\n<p>The trouble began, when I asked Copilot to take a screenshot of the<br \/>\nrunning Android app. I was hoping it would do something like:<\/p>\n<p>Boot emulator: emulator -avd Pixel_7_API_35<br \/>\nInstall and run the app.<br \/>\nadb shell screencap \/sdcard\/screenshot.png<br \/>\nadb pull \/sdcard\/screenshot.png<\/p>\n<p>Unfortunately, due to a configuration issue, it couldn\u2019t start the<br \/>\nAndroid emulator, and things quickly went off the rails! It instead<br \/>\ndecided to:<\/p>\n<p>Write a C# console app.<br \/>\nUse System.Drawing to <em>generate<\/em> an image of an Android emulator<br \/>\nand what it imagined the app would look like.<br \/>\nCheck in the screenshot to the repository, as if it was a real<br \/>\nscreenshot!<\/p>\n<p>This experience led us to come up with strategies for keeping Copilot<br \/>\non track:<\/p>\n<p>When assigning issues, always add links to documentation. Write the<br \/>\nissue in a way that a junior engineer (human) could pick up the<br \/>\ntask.<\/p>\n<p>Be terse and direct but not necessarily rude. Mention <em>how<\/em> you\u2019d<br \/>\nlike something done and don\u2019t expect Copilot to discover novel<br \/>\nsolutions on its own.<\/p>\n<p>Anticipate what might go wrong for Copilot. Tell it to \u201cgive up\u201d if it<br \/>\ncannot complete a task and report the error message.<\/p>\n<p>Write scripts for common tasks and put examples in<br \/>\ncopilot-instructions.md that Copilot can use as a reference.<\/p>\n<p>When Copilot does the wrong thing, it likely needs more context or<br \/>\nmore instructions. Think of this as \u201cdebugging\u201d your<br \/>\ncopilot-instructions.md file. Keep this in mind as you review pull<br \/>\nrequests from Copilot, ask it to update copilot-instructions.md<br \/>\nduring code review.<\/p>\n<h2>Conclusion<\/h2>\n<p>The GitHub Copilot Coding Agent is already showing strong potential in<br \/>\nour day-to-day development. We\u2019ve found it particularly effective for<br \/>\nhandling well-scoped, low-risk tasks. By leveraging Copilot for these<br \/>\n\u201ceasy\u201d issues, we save valuable engineering time and keep our team<br \/>\nfocused on more complex, high-impact work.<\/p>\n<p>Copilot has been most successful in the dotnet\/android repository,<br \/>\nwhere we\u2019ve specifically assigned it simpler refactoring-related<br \/>\ntasks. In the past 28 days we\u2019ve seen the following results with pull<br \/>\nrequests:<\/p>\n<p>Author<br \/>\nCount<br \/>\nMerge %<br \/>\nP50 time to merge<\/p>\n<p>@copilot<br \/>\n17<br \/>\n82.4%<br \/>\n10:15:34<\/p>\n<p>All others<br \/>\n49<br \/>\n87.8%<br \/>\n11:36:35<\/p>\n<p>P50 is 50th percentile, or what you might think of as the <em>most<br \/>\ncommon<\/em> time a PR could be merged. In dotnet\/android, Copilot has been<br \/>\npretty successful compared to all other PRs.<\/p>\n<p>In dotnet\/maui, we\u2019ve been more <em>optimistic<\/em>: assigning PRs we knew<br \/>\nmight be too tough for Copilot to complete:<\/p>\n<p>Author<br \/>\nCount<br \/>\nMerge %<br \/>\nP50 time to merge<\/p>\n<p>@copilot<br \/>\n54<br \/>\n16.7%<br \/>\n10:15:22<\/p>\n<p>All others<br \/>\n255<br \/>\n52.9%<br \/>\n14:36:47<\/p>\n<p>Take these numbers with a grain of salt, as we have certainly been<br \/>\nfocusing a decent amount of time on Copilot. We could easily be giving<br \/>\nCopilot PRs more attention as a result! Over the next several months,<br \/>\nwe should have a better picture of Copilot Coding Agent\u2019s full impact<br \/>\non the product.<\/p>\n<p>A few things that GitHub Copilot Coding Agent doesn\u2019t do yet:<\/p>\n<p><strong>Comment @copilot do this on an existing PR opened by a human<\/strong>:<br \/>\nThis would be beneficial to fix tiny \u201cnitpicks\u201d instead of waiting<br \/>\nfor one of our contributors (potentially a customer) to make the<br \/>\nchange.<\/p>\n<p><strong>Support running on Windows or macOS<\/strong>: This is unfortunately a big<br \/>\nneed for .NET MAUI, as the product targets Windows and iOS. Ideally,<br \/>\nwe could detect the issue or pull request is specific to a platform,<br \/>\nand programmatically choose which OS to run on.<\/p>\n<p>As the tool improves, we expect to expand its role in our development<br \/>\nprocess.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/maui-team-copilot-tips\/\">How the .NET MAUI Team uses GitHub Copilot for Productivity<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\">.NET Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Around the time of Microsoft Build 2025, the new GitHub Copilot Coding Agent was unveiled and made widely available across [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[7],"tags":[],"class_list":["post-2222","post","type-post","status-publish","format-standard","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=2222"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2222\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=2222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=2222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=2222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}