{"id":705,"date":"2026-05-17T02:48:37","date_gmt":"2026-05-16T23:48:37","guid":{"rendered":"https:\/\/biyer.com.tr\/?p=705"},"modified":"2026-05-17T02:48:37","modified_gmt":"2026-05-16T23:48:37","slug":"dungeons-desktops-building-a-procedurally-generated-roguelike-with-github-copilot-cli","status":"publish","type":"post","link":"https:\/\/biyer.com.tr\/?p=705","title":{"rendered":"Dungeons &amp; Desktops: Building a procedurally generated roguelike with GitHub Copilot CLI"},"content":{"rendered":"<p>I got nerd-sniped into the <a href=\"https:\/\/dev.to\/challenges\/github-2026-01-21\">GitHub Copilot CLI Challenge<\/a> and made a questionable decision: I turned my codebase into a roguelike dungeon.<\/p>\n<p>It started with a simple prompt: <code>Build a GitHub CLI extension in Go that takes the current repository and turns it into a playable roguelike dungeon, with dungeons generated with BSP [snip]<\/code>. And then <code>\/yolo<\/code> .<\/p>\n<p>The result is GitHub Dungeons, a terminal game that generates a dungeon from your codebase. Rooms, corridors, and enemies, all built from your repo and rendered right in your terminal. You navigate with arrow keys, fight bugs, and hunt for the exit. Every repository produces a different map. Every commit reshapes the layout. And if your HP hits zero, you start over.<\/p>\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"432\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.53.00-PM.png?resize=1024%2C432\" alt=\"Screenshot of 'gh dungeons'\" class=\"wp-image-95698\" style=\"width:755px;height:auto\" \/><\/figure>\n<p>&#128161; <strong>Fun fact:<\/strong> <code>\/yolo<\/code> (&ldquo;you only live once&rdquo;) is a Copilot CLI command (an alias for <code>\/allow-all<\/code>). Fitting, since roguelikes are built around permadeath. You really do only get one life.<\/p>\n<p>Roguelikes trace back to games like <em>Rogue<\/em> in the 1980s &ndash; terminal-based adventures where each run generated a new dungeon, and death meant starting over.<\/p>\n<p>That combination of procedural generation, permadeath, and text-based interfaces (later formalized in things like the &ldquo;Berlin Interpretation&rdquo;) makes the genre feel surprisingly modern, and a perfect fit for the command line.<\/p>\n<p>GitHub Dungeons leans into that tradition. It&rsquo;s written in Go, which I don&rsquo;t normally use, but working with Copilot meant I could focus on behavior instead of syntax.<\/p>\n<h3 class=\"wp-block-heading\" id=\"h-what-is-procedural-generation\">What is procedural generation?<\/h3>\n<p>Procedural generation (or &ldquo;procgen&rdquo; as the cool kids call it) is a way of creating content algorithmically instead of designing it by hand. In games, that usually means levels, maps, enemies, or items are generated at runtime using a set of rules plus a bit of randomness.<\/p>\n<p>So instead of designing <em>one<\/em> dungeon, you design a system that generates <em>many<\/em>.<\/p>\n<p>That&rsquo;s what gives roguelikes their replayability:<\/p>\n<ul class=\"wp-block-list\">\n<li>Every run is different<\/li>\n<li>Layouts change every time<\/li>\n<li>Something<\/li>\n<li>Something<\/li>\n<\/ul>\n<p>In GitHub Dungeons, that system is tied to your repo. The layout is seeded by your latest commit, so the same code produces the same dungeon, and every change reshapes it.<\/p>\n<h2 class=\"wp-block-heading\" id=\"h-so-how-does-a-repository-actually-become-a-dungeon\">So how does a repository actually become a dungeon?<\/h2>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\">\n<div class=\"mod-vh position-relative\" style=\"height: 0;padding-bottom: calc((9 \/ 16)*100%)\"><\/div>\n<\/div>\n<\/figure>\n<p>At a high level, GitHub Dungeon layouts are generated using Binary Space Partitioning (BSP), seeded by your repository&rsquo;s latest commit SHA (more on BSP in a bit). That means the same codebase produces a consistent layout, while still evolving as the code changes.<\/p>\n<p><strong>In practice<\/strong>:<\/p>\n<ul class=\"wp-block-list\">\n<li>The same commit always generates the same map<\/li>\n<li>Different repositories produce layouts that feel structurally distinct<\/li>\n<li>As the code changes, the dungeon evolves with it<\/li>\n<\/ul>\n<p>It&rsquo;s procedural generation&mdash;but tied directly to your codebase. That&rsquo;s the idea.<\/p>\n<p>The interesting part was actually building it.<\/p>\n<h2 class=\"wp-block-heading\" id=\"building-it-with-copilot-cli\">Building it with Copilot CLI<\/h2>\n<p>Working with <a href=\"https:\/\/github.com\/features\/copilot\/cli?utm_source=blog-dungeons-1-cta&amp;utm_medium=blog&amp;utm_campaign=dev-pod-copilot-cli-2026\">GitHub Copilot CLI<\/a> meant describing behavior instead of writing everything from scratch. One command that made a big difference was <code>\/delegate<\/code>. Instead of just generating code inline, <code>\/delegate<\/code> hands the task off to GitHub&rsquo;s Copilot coding agent running in the cloud.<\/p>\n<p>I could describe what I wanted in plain English, kick it off, and then go do something else while it worked independently. When it finished, it opened a pull request with the results.<\/p>\n<p>For example,<code>\/delegate Make each level progressively harder e.g. on level 2 there are extra baddies, but more health potions<\/code><\/p>\n<p>Copilot generated a solid first pass asynchronously, and I reviewed and tweaked the PR from there until the balance felt right. I took the same approach to other features like <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/pull\/4\">adding cheat codes that make the player invincible<\/a> (because why not).<\/p>\n<p>I even had Copilot generate a &ldquo;<a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/blob\/main\/.github\/agents\/dungeon-scribe.agent.md\">dungeon scribe<\/a>&rdquo; agent, a small helper that added <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/tree\/main\/docs\">documentation<\/a> and ASCII art diagrams to <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/blob\/main\/docs\/dungeon-generation.md\">explain how dungeons were generated<\/a>, which felt very on-brand for a terminal roguelike.<\/p>\n<p>I even had Copilot generate a <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/blob\/main\/.github\/agents\/dungeon-scribe.agent.md\">dungeon scribe agent<\/a> to create <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/tree\/main\/docs\">documentation<\/a> and <a href=\"https:\/\/github.com\/leereilly\/gh-dungeons\/blob\/main\/docs\/dungeon-generation.md\">explain how dungeons were generated<\/a> with ASCII art diagrams, which felt very on-brand for a terminal roguelike.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Using Copilot (especially with <code>\/delegate<\/code>) is like having an army of NPCs available to do whatever I want them to do.<\/p>\n<p><cite>Lee Reilly, Dungeon Master<\/cite><\/p><\/blockquote>\n<p>Working this way (describing features, delegating them to Copilot, and reviewing the resulting pull requests) meant I could spend less time on edge cases and boilerplate, and more time on the player experience, including adding easter eggs for players to discover. Iterating with Copilot let me stay in a game design mindset instead of constantly switching into implementation details. Because Copilot was handling most of the build and scaffolding, I could stay in the flow of designing mechanics, testing ideas, and figuring out what actually made the game fun.<\/p>\n<h3 class=\"wp-block-heading\" id=\"h-procedurally-generated-levels-with-bsp\">Procedurally generated levels (with BSP)<\/h3>\n<p>At the heart of each dungeon design is a technique called <strong>Binary Space Partitioning (BSP),<\/strong> which is a great thing to casually mention alongside middle-out compression if you want to impress your friends and colleagues. It sounds intimidating, but the idea is surprisingly simple: keep splitting a space into smaller chunks until you have a bunch of rooms you can connect.<\/p>\n<h3 class=\"wp-block-heading\" id=\"why-bsp-works-so-well-for-roguelikes\">Why BSP works so well for roguelikes<\/h3>\n<p>Roguelikes need maps that feel:<\/p>\n<ul class=\"wp-block-list\">\n<li>Structured (not completely random nonsense)<\/li>\n<li>Replayable (different every run)<\/li>\n<li>Navigable (no dead ends or impossible layouts)<\/li>\n<\/ul>\n<p>BSP hits a sweet spot. It gives you:<\/p>\n<ul class=\"wp-block-list\">\n<li>Clean, rectangular rooms<\/li>\n<li>Guaranteed connectivity<\/li>\n<li>Just enough randomness to feel organic<\/li>\n<\/ul>\n<p>Here&rsquo;s how it works&hellip;<\/p>\n<h4 class=\"wp-block-heading\" id=\"1-start-with-a-big-empty-space\">1. Start with a big empty space<\/h4>\n<p>Everything begins as one big rectangle: your entire dungeon.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"431\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.53.09-PM.png?resize=1024%2C431\" alt=\"Screenshot of 'entire map' and 'start with one rectangle'.\" class=\"wp-image-95699\" \/><\/figure>\n<h4 class=\"wp-block-heading\" id=\"2-split-it-recursively\">2. Split it (recursively)<\/h4>\n<p>We split the space into two regions.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"434\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.53.33-PM.png?resize=1024%2C434\" alt=\"Screenshot showing two boxes: left and right.\" class=\"wp-image-95700\" \/><\/figure>\n<p>Then split those again.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"433\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.53.44-PM.png?resize=1024%2C433\" alt=\"Screenshot showing three boxes: A, B, and C.\" class=\"wp-image-95701\" \/><\/figure>\n<p>And again.<\/p>\n<p>Each split can be horizontal or vertical.<\/p>\n<h4 class=\"wp-block-heading\" id=\"3-stop-when-it-gets-too-small\">3. Stop when it gets too small<\/h4>\n<p>We keep splitting until regions are too small to fit a room.<\/p>\n<p>That creates a bunch of &ldquo;leaf&rdquo; regions, the final building blocks.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"433\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.53.54-PM.png?resize=1024%2C433\" alt=\"Screenshot showing six boxes: A, B, C, D, E, and F.\" class=\"wp-image-95702\" \/><\/figure>\n<h4 class=\"wp-block-heading\" id=\"4-turn-each-region-into-a-room\">4. Turn each region into a room<\/h4>\n<p>Each leaf becomes a room, but not perfectly aligned. We randomize size and position slightly.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"434\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.54.03-PM.png?resize=1024%2C434\" alt=\"Screenshot showing six rooms.\" class=\"wp-image-95703\" \/><\/figure>\n<p>That slight randomness is what stops everything feeling too grid-like.<\/p>\n<h4 class=\"wp-block-heading\" id=\"5-connect-rooms-with-corridors\">5. Connect rooms with corridors<\/h4>\n<p>Now we connect rooms by walking back up the tree and linking siblings.<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"435\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.54.12-PM.png?resize=1024%2C435\" alt=\"Screenshot showing rooms 1 and 2 separated.\" class=\"wp-image-95704\" \/><\/figure>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"433\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.54.22-PM.png?resize=1024%2C433\" alt=\"Screenshot showing rooms 1 and 2 connected.\" class=\"wp-image-95705\" \/><\/figure>\n<p>Each connection is an L-shape:<\/p>\n<h4 class=\"wp-block-heading\" id=\"6-end-result-structured-chaos\">6. End result: structured chaos<\/h4>\n<p>Put it all together and you get something like this:<\/p>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-recalc-dims=\"1\" loading=\"lazy\" height=\"433\" width=\"1024\" src=\"https:\/\/github.blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-01-at-3.54.28-PM.png?resize=1024%2C433\" alt=\"Screenshot showing the final room layout.\" class=\"wp-image-95706\" \/><\/figure>\n<ul class=\"wp-block-list\">\n<li>Rooms feel intentional<\/li>\n<li>Corridors make everything reachable<\/li>\n<li>Every run is different (but reproducible with a seed)<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\" id=\"why-this-lands-so-well\">Why this lands so well<\/h2>\n<p>What I like about BSP is that it feels designed, even though it isn&rsquo;t.<\/p>\n<p>It avoids the two big problems of procedural generation: pure randomness (messy), and rigid grids (predictable, boring). Instead, you get something in between&hellip; and sometimes beautiful.<\/p>\n<h2 class=\"wp-block-heading\" id=\"how-to-install-and-play-it\">How to install and play it<\/h2>\n<p>If you want to see what your own codebase looks like as a dungeon, and you already have <a href=\"https:\/\/github.com\/features\/copilot\/cli?utm_source=blog-dungeons-1-cta&amp;utm_medium=blog&amp;utm_campaign=dev-pod-copilot-cli-2026\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub Copilot CLI<\/a> installed, you can run:<\/p>\n<div class=\"wp-block-code-wrapper\">\n<pre class=\"wp-block-code language-plaintext\"><code>gh extension install leereilly\/gh-dungeons <\/code><\/pre>\n<\/div>\n<p>After that, run <code>gh dungeons<\/code> to transform your repository into a custom dungeon, ready to be conquered. Control your hero with WASD, arrow keys, or Vim keys.<\/p>\n<p>Your goal is to find the hidden door and escape from (and attack!) enemies over five levels. I&rsquo;ve added fun features like fog of war that limit visibility, auto-attack, ability to track stats like kills and conquered levels, and more that you&rsquo;ll have to discover yourself.<\/p>\n<h2 class=\"wp-block-heading\" id=\"danger-zone\">Danger zone!<\/h2>\n<p>If you&rsquo;re feeling reckless, play it on crazy mode: you can set up a pre-commit hook that deletes your saved changes unless you beat the entire game. <\/p>\n<p>&#9888;&#65039; <em><strong>WARNING: Do not do this<\/strong> unless you fully understand what this will do to your repository, you&rsquo;ll lose saved work and probably some sanity as well.<\/em><\/p>\n<div class=\"wp-block-code-wrapper\">\n<pre class=\"wp-block-code language-plaintext\"><code># Create the pre-commit hook \ncat &gt; .git\/hooks\/pre-commit &lt;&lt; 'EOF' \n#!\/bin\/bash \ngh dungeons \nif [ $? -ne 0 ]; then \n    echo \"You died! Your changes have been stashed into oblivion...\" \n    git stash &amp;&amp; git stash drop stash@{0} \n    exit 1 \nfi \nEOF \n \n# Make it executable \nchmod +x .git\/hooks\/pre-commit \n \n# To be clear, you&rsquo;ll lose all your uncommited changes if you enable this \n# and fail to beat the dungeon, adventurer. <\/code><\/pre>\n<\/div>\n<p><em>(Editor&rsquo;s note: Please, please, please do not do this. We are not responsible for any lost work. But Lee definitely is.)<\/em><\/p>\n<h2 class=\"wp-block-heading\" id=\"h-take-this-with-you\">Take this with you<\/h2>\n<p>This started as a throwaway experiment, but it changed how I think about <a href=\"https:\/\/github.com\/features\/copilot\/cli?utm_source=blog-dungeons-1-cta&amp;utm_medium=blog&amp;utm_campaign=dev-pod-copilot-cli-2026\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub Copilot CLI<\/a>.<\/p>\n<p>I was able to MVP it quickly, iterate on the parts that mattered, and let Copilot handle the heavy lifting, things like BSP generation and even monsters and movement defined in a slightly cursed YAML file of Yendor.<\/p>\n<\/p>\n<p>The post <a href=\"https:\/\/github.blog\/ai-and-ml\/github-copilot\/dungeons-desktops-building-a-procedurally-generated-roguelike-with-github-copilot-cli\/\">Dungeons &amp; Desktops: Building a procedurally generated roguelike with GitHub Copilot CLI<\/a> appeared first on <a href=\"https:\/\/github.blog\">The GitHub Blog<\/a>.<\/p>\n<p><a href=\"https:\/\/github.blog\/ai-and-ml\/github-copilot\/dungeons-desktops-building-a-procedurally-generated-roguelike-with-github-copilot-cli\/\" target=\"_blank\">Orijinal Kayna\u011fa Git<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I got nerd-sniped into the GitHub Copilot CLI Challenge and made a questionable decision: I turned my codebase into a roguelike dungeon. It started with a simple prompt: Build a GitHub CLI extension in Go that takes the current repository and turns it into a playable roguelike dungeon, with dungeons generated with BSP [snip]. And [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":707,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-705","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-genel"],"_links":{"self":[{"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/posts\/705","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=705"}],"version-history":[{"count":1,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/posts\/705\/revisions"}],"predecessor-version":[{"id":706,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/posts\/705\/revisions\/706"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=\/wp\/v2\/media\/707"}],"wp:attachment":[{"href":"https:\/\/biyer.com.tr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=705"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=705"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/biyer.com.tr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=705"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}