<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: crimson206</title>
    <description>The latest articles on DEV Community by crimson206 (@crimson206).</description>
    <link>https://dev.to/crimson206</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1005611%2F17a74f8e-82bc-4561-9960-af124dcb6fc4.png</url>
      <title>DEV Community: crimson206</title>
      <link>https://dev.to/crimson206</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crimson206"/>
    <language>en</language>
    <item>
      <title>One Repo, One Package: Where the Review Trail Lives</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Wed, 07 Oct 2026 12:19:45 +0000</pubDate>
      <link>https://dev.to/crimson206/one-repo-one-package-where-the-review-trail-lives-4fok</link>
      <guid>https://dev.to/crimson206/one-repo-one-package-where-the-review-trail-lives-4fok</guid>
      <description>&lt;p&gt;In &lt;a href="https://microwiseai.com/blog/mwd-one-repo-one-package" rel="noopener noreferrer"&gt;our first post on MWD&lt;/a&gt; we described the rule we build with: &lt;strong&gt;one repo = one package&lt;/strong&gt;. Packages depend on each other only through published, versioned releases. At the end we admitted a cost: a change that spans several packages turns into several releases, and keeping versions aligned takes real care.&lt;/p&gt;

&lt;p&gt;A reader replied with a good question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'd keep the package release and downstream version bump in the same review trail, so the interface change stays visible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post is our answer. We agree the change has to stay visible. We disagree that it needs one shared review trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the review trail lives
&lt;/h2&gt;

&lt;p&gt;When a change in package A forces a change in package B, two decisions are made, in two places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; decides &lt;em&gt;what&lt;/em&gt; changed and &lt;em&gt;why&lt;/em&gt;, and releases it under a version tag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B&lt;/strong&gt; decides &lt;em&gt;which&lt;/em&gt; version of A to take and &lt;em&gt;why&lt;/em&gt;, and pins it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both decisions belong in the commit history of the repository that made them. A's commit says what the interface change is. B's commit says "took A 0.1.1 because of X." The pinned version number is the link between them: from B you can find the exact release of A, and from A's tag you can find the commit that explains it.&lt;/p&gt;

&lt;p&gt;So the histories stay separate, and each repository keeps a complete record of its own reasons, but the information isn't cut off. You follow the version number from one history to the other.&lt;/p&gt;

&lt;p&gt;To make this concrete, we'll use a small example workspace, &lt;code&gt;acme&lt;/code&gt;, built for this post. It has five repositories: a shared &lt;code&gt;core&lt;/code&gt; package, a &lt;code&gt;worker&lt;/code&gt; package that runs tasks and is deployed to production, a &lt;code&gt;cli&lt;/code&gt; app, a &lt;code&gt;dashboard&lt;/code&gt; app, and a &lt;code&gt;worker-deploy&lt;/code&gt; project. The names, commits and versions are made up; the tool output further down is real, run against that workspace.&lt;/p&gt;

&lt;p&gt;The change: &lt;code&gt;core&lt;/code&gt; gets an optional task priority. Here's how it moves through the repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;core&lt;/strong&gt;: &lt;code&gt;feat(core): optional task priority (low|normal|high, default normal)&lt;/code&gt;, then &lt;code&gt;chore: release v1.3.0&lt;/code&gt; and tag &lt;code&gt;v1.3.0&lt;/code&gt;. What the new field is and how it's validated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;worker&lt;/strong&gt;: &lt;code&gt;chore(deps): @acme/core lower bound ^1.3.0 (task priority)&lt;/code&gt;, &lt;code&gt;feat(worker): run high-priority tasks first&lt;/code&gt;, then &lt;code&gt;lock @acme/core 1.3.0&lt;/code&gt; and its own release, &lt;code&gt;v0.5.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cli&lt;/strong&gt;: &lt;code&gt;chore(deps): apply @acme/core 1.3.0&lt;/code&gt;, &lt;code&gt;feat(cli): acme submit --priority &amp;lt;low|normal|high&amp;gt;&lt;/code&gt;, then &lt;code&gt;v0.4.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;worker-deploy&lt;/strong&gt;: &lt;code&gt;chore(deps): pin @acme/worker 0.5.0 (high-priority tasks run first)&lt;/code&gt; (more on this one below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why not one review space per change instead? Because the boundary isn't clear. A change in core touches the worker and the cli; the worker takes core directly and is deployed by yet another project; the dashboard depends on core too but doesn't need the new field yet. If every dependency edge gets a review space, you have to decide where each one starts and ends, and the number of spaces grows with the number of edges, not the number of packages. We would rather keep one rule that scales: every repository explains itself, and versions connect them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes wrong if you do it naively
&lt;/h2&gt;

&lt;p&gt;The rule alone doesn't make any of this easy. If you follow one repo = one package and change nothing else, you hit four problems quickly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The story scatters.&lt;/strong&gt; One change produces commits in four or five repositories. Each history is fine on its own, but nobody sees the whole sequence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You don't know who is affected.&lt;/strong&gt; When core changes, which packages depend on it, and which of them need a new release?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versions drift.&lt;/strong&gt; Some packages pin the new version and others still ask for the old range. It isn't always a bug, but you have to look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local, installed and deployed copies disagree.&lt;/strong&gt; The code in your working tree, the version installed on your machine and the version running in production can all be different, and nothing tells you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are reasons to give up the rule. They are reasons to make the connections visible. Here are the tools we use for that. The output below is real, run against the example workspace from the change above; its root path is shortened to &lt;code&gt;~/acme&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the hierarchy: nested repos, two views
&lt;/h2&gt;

&lt;p&gt;Splitting into many repositories doesn't mean giving up structure. A workspace still nests: a &lt;code&gt;packages/&lt;/code&gt; folder for libraries, a &lt;code&gt;projects/&lt;/code&gt; folder for apps, and each entry is its own Git repository. The gitdot names from &lt;a href="https://microwiseai.com/blog/mwd-one-repo-one-package" rel="noopener noreferrer"&gt;the first post&lt;/a&gt; carry the same structure into the remote: &lt;code&gt;packages/core&lt;/code&gt; on disk is &lt;code&gt;acme/taskq.packages.core&lt;/code&gt; on the Git host.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://microwiseai.com/blog/r/git-nested" rel="noopener noreferrer"&gt;&lt;code&gt;git-nested&lt;/code&gt;&lt;/a&gt;, which we introduced last time as a live view of changes across nested repositories, can show the workspace from either side. By folder, with each repository's remote:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv15ghh11x50x62vv83rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv15ghh11x50x62vv83rl.png" alt="git-nested scan output by folder for ~/acme: packages/ with core and worker, projects/ with cli, dashboard (1 uncommitted change) and worker-deploy, each line ending in its remote such as git@git.example.com:acme/taskq.packages.core.git" width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And by repository name, splitting each gitdot name on its dots:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhyj8x3bi8tq3blglugfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhyj8x3bi8tq3blglugfv.png" alt="git-nested scan --gitdot output: git.example.com / acme / taskq / packages (core, worker) and projects (cli, dashboard, worker-deploy), the same tree as the folder view" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The web view shows the same thing side by side: the repositories by local path on the left, and by remote URL on the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ab0f5paaup95n8c982i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ab0f5paaup95n8c982i.png" alt="git-nested web view of the same 5 repositories. Left, by local path: packages (core, worker) and projects (cli, dashboard, worker-deploy). Right, by remote URL: git.example.com › acme › taskq, then the same packages and projects folders with the same entries. dashboard is highlighted with 1 change in both." width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same hierarchy comes out of both the folders and the repository names. Neither depends on the other: clone by name and you can rebuild the folders; look at a folder and you know the repository's name. One repo = one package splits the code, not the structure. (The &lt;code&gt;(1)&lt;/code&gt; on dashboard is one uncommitted file; we'll come back to it.)&lt;/p&gt;

&lt;p&gt;git-nested went through this split itself. It used to be one repository; it is now &lt;code&gt;core&lt;/code&gt;, &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;ui&lt;/code&gt; packages plus a &lt;code&gt;cli&lt;/code&gt; project, each in its own repository. The original repository became the cli project rather than being replaced, so its history carried over intact, and the new packages start with their own histories. The cli's commit says it is now assembled from them, and its dependencies name the versions it takes. That's the pattern of this post on a small scale: independent histories, connections kept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following one change across repos: cscan
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cscan&lt;/code&gt; collects commits from every repository under a folder into one timeline. Here it is for the change above, the day core added task priority, grouped by repository (times in UTC):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flk5yn5p5jpuivz2mwlc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flk5yn5p5jpuivz2mwlc3.png" alt="cscan output for ~/acme on 2026-09-22, 11 commits in 4 repos grouped by repository: core adds optional task priority, tests it and releases v1.3.0; worker raises the @acme/core lower bound to ^1.3.0, runs high-priority tasks first, locks @acme/core 1.3.0 and releases v0.5.0; cli applies @acme/core 1.3.0, adds --priority and releases v0.4.0; worker-deploy pins @acme/worker 0.5.0" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each line is still a commit in its own repository, with its own reason. cscan doesn't merge anything. It puts the separate histories next to each other so you can read the whole sequence: core added the feature and released, the worker raised its lower bound, then locked the new version and released, the cli followed, and the deploy project pinned the released worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is affected, and are versions aligned: mwd-deps
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;mwd-deps&lt;/code&gt; reads dependency declarations. &lt;code&gt;sync-check&lt;/code&gt; looks at every local package in a folder and reports where packages ask for different versions of the same dependency:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9valexitht27cq6h9p9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9valexitht27cq6h9p9l.png" alt="mwd-deps sync-check output for the @acme scope: 1 mismatch. @acme/core is requested as ^1.3.0 by @acme/worker and @acme/cli, and as ^1.2.0 by @acme/dashboard" width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This doubles as the answer to "who depends on core?": every package that declares it is listed, along with the range it asks for. Not every mismatch is a bug. &lt;code&gt;^1.2.0&lt;/code&gt; still accepts 1.3.0, so the dashboard can still end up with the new version installed. But the list shows exactly where a decision was made and where it wasn't yet. Here the dashboard is the one that hasn't decided, and it's also the repository git-nested showed with uncommitted work: someone is in the middle of adding the priority column. When that lands, its commit should say which version of core it now needs, and why. mwd-deps also has &lt;code&gt;dependents&lt;/code&gt; and &lt;code&gt;impact&lt;/code&gt; commands that answer the same question from the package registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local vs installed vs published: verscan
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;verscan&lt;/code&gt; walks a folder and compares, for each package, the version in the working tree, the version installed as a command on the machine, and the latest published version in the registry. Nothing in the example workspace is published, so there's nothing useful to show here, but on a real workspace it lists the packages where the three disagree: a release that was never published, a CLI that's installed globally at an older version, a &lt;code&gt;--version&lt;/code&gt; flag that prints the wrong number.&lt;/p&gt;

&lt;p&gt;Most of what it finds is expected, such as an app that's never meant to be published. The point is that the three versions are checked, not assumed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A common mistake: deploying what wasn't released
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;worker&lt;/code&gt; package is what runs in production. The tempting way to ship a change is to deploy straight from its working tree, then release. In the example workspace, that's how the previous worker release went:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fye13zkbb7qg0kmuenb3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fye13zkbb7qg0kmuenb3g.png" alt="cscan output for ~/acme from 2026-09-15 to 2026-09-17: in worker, " width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deploy commit comes 24 minutes &lt;em&gt;before&lt;/em&gt; the &lt;code&gt;v0.4.0&lt;/code&gt; release. For those 24 minutes, production ran code that existed only in a local checkout. Even if the release that follows differs only in its version number, the rule is broken: the deployed worker has no published version to point to, so the trail from "what's running" back to "which release, and why" is missing. And nothing forces the release to match what was deployed.&lt;/p&gt;

&lt;p&gt;The fix is structural, not a reminder. A separate deploy project, &lt;code&gt;worker-deploy&lt;/code&gt;, doesn't contain the worker's code. It installs a published, exactly pinned version of &lt;code&gt;@acme/worker&lt;/code&gt; and deploys only that. Upgrading the worker then means: release the package, bump the pin in the deploy project with a commit that says why, then deploy. That's the last line of the earlier timeline: &lt;code&gt;pin @acme/worker 0.5.0 (high-priority tasks run first)&lt;/code&gt;, after the worker's &lt;code&gt;v0.5.0&lt;/code&gt; release. The deploy project's history is the record of what ran in production, and each entry points to a release.&lt;/p&gt;

&lt;p&gt;That's the same pattern as the rest of this post: the deployment becomes one more repository that writes down which version it took.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;One repo = one package means a cross-package change leaves several commits in several histories. We think that's fine, as long as each repository records its own reason and the version numbers connect them. A shared review space for every dependency would be hard to define and hard to keep up.&lt;/p&gt;

&lt;p&gt;What we needed instead was to make the connections visible: the hierarchy (git-nested), the timeline across repositories (cscan), who depends on what (mwd-deps) and which versions are actually where (verscan). These tools don't change how the work is split. They let us read it as one story when we need to.&lt;/p&gt;

</description>
      <category>mwd</category>
      <category>ai</category>
      <category>developertools</category>
      <category>git</category>
    </item>
    <item>
      <title>One Repo, One Package: How We Structure Code for AI Agents</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Wed, 30 Sep 2026 08:41:44 +0000</pubDate>
      <link>https://dev.to/crimson206/one-repo-one-package-how-we-structure-code-for-ai-agents-5app</link>
      <guid>https://dev.to/crimson206/one-repo-one-package-how-we-structure-code-for-ai-agents-5app</guid>
      <description>&lt;p&gt;Most development practices were designed around people: how teams split work, review each other's changes, and ship together. Now more and more of the code is written by AI agents, so we started from a different question. What structure makes an agent's work easy to scope, easy to check and easy to undo?&lt;/p&gt;

&lt;p&gt;Our answer is a methodology we call &lt;strong&gt;MWD (Microwise Development)&lt;/strong&gt;. It has one core rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;One repo = one package.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every package lives in its own Git repository. Packages stay small and do one thing. They depend on each other only through &lt;strong&gt;published, versioned releases&lt;/strong&gt;, never through local paths like &lt;code&gt;file:../&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhrqgbx4ppwjzbul0wgd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhrqgbx4ppwjzbul0wgd5.png" alt="Monorepo vs one repo = one package. Left: one agent looking over one big monorepo, everything in reach. Right: three repos, each one package with its own agent, linked only by published versions such as v1.4.2 and v2.0.1." width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters when agents write the code
&lt;/h2&gt;

&lt;p&gt;An AI coding session works inside a boundary, and the useful question is what that boundary contains.&lt;/p&gt;

&lt;p&gt;In a large shared codebase, an agent asked to fix one module can see, and often touch, everything around it. The change you asked for comes back mixed with changes you didn't ask for. When something breaks, it is hard to say how far back you need to roll.&lt;/p&gt;

&lt;p&gt;When the package &lt;em&gt;is&lt;/em&gt; the repository, the boundary becomes concrete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope.&lt;/strong&gt; An agent working on a package opens that repository. What is in front of it is the package and the versions it depends on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallelism.&lt;/strong&gt; Two agents working on two packages are working in two repositories. They don't share a working tree, so they don't collide in one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback.&lt;/strong&gt; A package has its own history and its own releases. If a release is bad, consumers go back to the previous version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can approximate some of this inside a monorepo with conventions and tooling. We chose the repository boundary because git, CI, permissions and releases already respect it.&lt;/p&gt;

&lt;p&gt;The rule is simple, but following it creates two practical problems right away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem one: a lot of repositories
&lt;/h2&gt;

&lt;p&gt;If every package is a repository, you end up with many repositories: dozens at first, then more. A monorepo gives you structure for free, because folders nest. A flat list of repositories on a Git host doesn't.&lt;/p&gt;

&lt;p&gt;We didn't want to give up the one-repo rule to get structure back, so we put the structure into the &lt;strong&gt;repository name&lt;/strong&gt; instead. This is &lt;strong&gt;gitdot&lt;/strong&gt;, a naming syntax that uses dots to express hierarchy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitlab.com/microwiseai/glpkg.cli
gitlab.com/microwiseai/glpkg.adapters.npm
gitlab.com/microwiseai/glpkg.adapters.pypi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gitdot reads those names as a tree: a &lt;code&gt;glpkg&lt;/code&gt; group containing &lt;code&gt;cli&lt;/code&gt; and an &lt;code&gt;adapters&lt;/code&gt; group, which in turn holds &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;pypi&lt;/code&gt;. The hierarchy you would have expressed with folders in a monorepo now lives in the name, and so in the URL of every repository. It works on the Git hosts you already use, such as GitHub and GitLab. gitdot doesn't host anything itself; it's an organizing layer on top of the platform.&lt;/p&gt;

&lt;p&gt;Here are our own glpkg repositories, first as GitLab lists them and then as gitdot shows the same repositories:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbq4xbbwm2zhfpp2zjzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbq4xbbwm2zhfpp2zjzo.png" alt="Our glpkg repositories on GitLab: a flat list of names like glpkg.adapters.npm, glpkg.cli and glpkg.publisher" width="800" height="615"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Before: GitLab shows a flat list.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F00vzdvaju4dkeynmot14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F00vzdvaju4dkeynmot14.png" alt="The same repositories in gitdot: a tree with microwiseai &gt; glpkg &gt; adapters (npm, pypi, go, nuget, generic) and packages" width="720" height="918"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After: gitdot turns the dotted names into a tree.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the structure in the names, grouping, listing and cloning "everything under &lt;code&gt;glpkg.adapters&lt;/code&gt;" become operations on names.&lt;/p&gt;
&lt;h2&gt;
  
  
  Problem two: a lot of packages to publish
&lt;/h2&gt;

&lt;p&gt;The second problem follows from the first. If packages depend on each other only through published versions, every package has to be &lt;strong&gt;published&lt;/strong&gt;, often and in large numbers. A fix to one small package means a new release, and then consumers install that release.&lt;/p&gt;

&lt;p&gt;Where do all those releases go?&lt;/p&gt;

&lt;p&gt;The obvious answer is the public registries: npm, PyPI and the others. That doesn't fit what we're doing. Many of these packages are small internal building blocks. They're useful to us, but they don't belong in a public index that other developers search. Publishing hundreds of them would add noise to a shared space. It would also tie our naming to whatever is still free there, and many good names and scopes were claimed long ago.&lt;/p&gt;

&lt;p&gt;What we wanted was a registry of our own that we could publish to as often as we like, under names we choose, without touching the public registries.&lt;/p&gt;

&lt;p&gt;That's what &lt;strong&gt;glpkg&lt;/strong&gt; does. It publishes packages to, and installs them from, a GitLab package registry that belongs to your group. From the developer's side (or the agent's side), it feels like any other package manager.&lt;/p&gt;

&lt;p&gt;Here's a real example. &lt;strong&gt;git-nested&lt;/strong&gt; is a small tool we built for this way of working. With one repo per package, a workspace fills up with Git repositories nested inside folders, and git-nested shows all of them as one tree in the browser, with each repository's uncommitted changes updating as files change. We publish it with glpkg to our group's registry, and because its repository (&lt;a href="https://gitlab.com/microwiseai/mwd-tools.git-nested" rel="noopener noreferrer"&gt;gitlab.com/microwiseai/mwd-tools.git-nested&lt;/a&gt;) is public, you can install it without a token. It's a command-line tool, so it goes in globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @glpkg/cli
glpkg &lt;span class="nb"&gt;install&lt;/span&gt; @mwd-tools/git-nested &lt;span class="nt"&gt;--group&lt;/span&gt; microwiseai &lt;span class="nt"&gt;-g&lt;/span&gt;
git-nested &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--group&lt;/code&gt; tells glpkg which group's registry to install from. glpkg takes care of the registry configuration and authentication, so installing one of our packages looks the same as installing a public one. It supports npm, PyPI, Go modules, NuGet and generic packages.&lt;/p&gt;

&lt;p&gt;In our workflow the loop for a change is always the same: commit, publish a new version, install it where it's needed. Agents follow the same loop as people, with the same commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why GitLab
&lt;/h2&gt;

&lt;p&gt;We looked at the usual candidates. Publishing everything to the public npm registry defeated the purpose. GitHub Packages integrates well with GitHub, but it has no generic package type for arbitrary artifacts. A self-hosted registry like Verdaccio handles npm only, and it's one more server to run.&lt;/p&gt;

&lt;p&gt;GitLab was the one product that gave us all of these together, on its free hosted tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;private packages&lt;/li&gt;
&lt;li&gt;several package formats plus a generic registry&lt;/li&gt;
&lt;li&gt;Git hosting and CI in the same place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitLab doesn't have the widest format coverage; dedicated artifact managers support more. For us, the combination mattered more. We'll go deeper into this comparison in a follow-up post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;MWD starts from one rule, one repo = one package, because it gives an AI agent a clear boundary to work in and gives us a clean unit to review and roll back. The rest of the tooling exists to make that rule livable: gitdot keeps many repositories organized, and glpkg keeps many packages flowing.&lt;/p&gt;

&lt;p&gt;gitdot, glpkg and git-nested aren't the only tools. Along the way we've built several others for working this way, such as linting and dependency checks, and we use them every day. Most of those are still internal. We hope to share more of them over time.&lt;/p&gt;

&lt;p&gt;The rule has costs too. A change that spans several packages turns into several releases, and keeping versions aligned across repositories takes real care. We'll write about those trade-offs as well.&lt;/p&gt;

&lt;p&gt;If you're working with AI agents on a codebase that keeps growing, we hope this gives you another way to think about where the boundaries go.&lt;/p&gt;

</description>
      <category>mwd</category>
      <category>ai</category>
      <category>developertools</category>
      <category>git</category>
    </item>
    <item>
      <title>IST: Running AI Coding Sessions as a Team</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Sat, 26 Sep 2026 11:27:54 +0000</pubDate>
      <link>https://dev.to/crimson206/ist-running-ai-coding-sessions-as-a-team-5h31</link>
      <guid>https://dev.to/crimson206/ist-running-ai-coding-sessions-as-a-team-5h31</guid>
      <description>&lt;p&gt;Most of us use AI to write code the same way: one chat window, one agent, one task at a time. It is a good default — until the work outgrows a single conversation, and that one thread becomes the bottleneck.&lt;/p&gt;

&lt;p&gt;IST takes a different approach. Instead of a single agent, it runs &lt;strong&gt;multiple sessions that coordinate like a team&lt;/strong&gt;: a &lt;em&gt;manager&lt;/em&gt; that plans and delegates, and &lt;em&gt;workers&lt;/em&gt; that carry out tasks in parallel. The manager rarely touches the code itself. It decomposes the work, hands each piece to a worker, reviews what comes back, and keeps everything moving toward the goal.&lt;/p&gt;

&lt;p&gt;Here is what that looks like when several sessions run at once:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xO7QLipJWug" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  A team, not a chatbot
&lt;/h2&gt;

&lt;p&gt;A single agent is a capable individual contributor. But an individual has limits: one context window, one train of thought, one thing in flight. Scale the ambition — a migration across dozens of files, a feature that spans several services, a batch of independent tasks — and you feel those limits fast.&lt;/p&gt;

&lt;p&gt;IST reframes the unit of work from &lt;em&gt;a conversation&lt;/em&gt; into &lt;em&gt;a team&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sessions&lt;/strong&gt; are independent agents, each with its own context and workspace. You start and manage them with a single command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messaging&lt;/strong&gt; lets sessions talk to one another — a manager assigns a task, a worker reports back — so coordination is explicit rather than improvised.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; watches every session at once, surfacing the moment one needs a decision or finishes its work, so nothing stalls in silence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of these primitives sits a simple pattern we call &lt;strong&gt;TDA (Top-Down Agent)&lt;/strong&gt;: the manager owns the plan and the delegation; workers own the execution. The manager stays at altitude — deciding &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;who&lt;/em&gt; — while workers handle the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;Parallelism is the obvious win: several workers can move on several fronts while the manager holds the thread. But the quieter benefit is &lt;strong&gt;separation of concerns&lt;/strong&gt;. The manager is never buried in diffs, so it stays free to plan, sequence, and verify. Workers are never distracted by the big picture, so each one focuses on a single well-scoped task and returns a clean result. The structure itself makes the work more legible — and, in our experience, more correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;The best way to understand IST is to run it. Our getting-started guide takes you from zero to your first manager-and-worker setup in a few minutes:&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://docs.ist.microwiseai.com/docs/guides/getting-started" rel="noopener noreferrer"&gt;Getting Started with IST&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you build something with it — or break something interesting — we would love to hear about it. Follow along as we build MicrowiseAI in the open.&lt;/p&gt;

</description>
      <category>ist</category>
      <category>multiagent</category>
      <category>ai</category>
      <category>developertools</category>
    </item>
    <item>
      <title>Don't delegate too much to Claude Code.</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Mon, 08 Sep 2025 23:06:41 +0000</pubDate>
      <link>https://dev.to/crimson206/dont-delegate-too-much-to-claude-code-1dpo</link>
      <guid>https://dev.to/crimson206/dont-delegate-too-much-to-claude-code-1dpo</guid>
      <description>&lt;p&gt;Since Claude Code handles most things pretty well, I tend to just approve permission requests as they come in. But this makes it hard for both me and Claude Code to know if the code is actually on the right track. While it might be handling the small details fine, the overall flow could be a complete mess.&lt;/p&gt;

&lt;p&gt;Even if I keep hitting "yes! yes!" in the moment, I need to completely reset the allow settings the next day.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>productivity</category>
    </item>
    <item>
      <title>From Google Maps to OpenStreetMap: A Journey of Trade-offs in Location Services</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Fri, 05 Sep 2025 12:02:17 +0000</pubDate>
      <link>https://dev.to/crimson206/from-google-maps-to-openstreetmap-a-journey-of-trade-offs-in-location-services-1cfm</link>
      <guid>https://dev.to/crimson206/from-google-maps-to-openstreetmap-a-journey-of-trade-offs-in-location-services-1cfm</guid>
      <description>&lt;p&gt;When building a location-based application, I needed to implement a feature that would allow users to click on a map and retrieve coordinates. What seemed like a straightforward requirement turned into an exploration of different mapping solutions and their inherent trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Google Maps Temptation
&lt;/h2&gt;

&lt;p&gt;My initial instinct was to leverage Google Maps - it's familiar to users and provides excellent search functionality. On the web version, Google Maps generates URLs like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.google.com/maps/place/N+Seoul+Tower/data=!3m1!4b1!4m6!3m5!1s0x357ca257a88e6aa9:0x5cf8577c2e7982a5!8m2!3d37.5511694!4d126.9882266!16zL20vMDJxcGYx?entry=ttu&amp;amp;g_ep=EgoyMDI1MDkwMi4wIKXMDSoASAFQAw%3D%3D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These URLs contain location data and place IDs that can be parsed for coordinates. However, on mobile devices, you can't directly access these URLs. Instead, the share function provides short links like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://naver.me/xZjKJ9SA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While these can be resolved through redirects to get the full URL, this introduces latency - an acceptable trade-off for the familiar Google Maps experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stability Problem
&lt;/h2&gt;

&lt;p&gt;The real showstopper wasn't the user experience or performance concerns. It was &lt;strong&gt;stability&lt;/strong&gt;. The URL structure I was parsing wasn't a JSON API response or official documentation - it was essentially reverse-engineering Google's internal URL format.&lt;/p&gt;

&lt;p&gt;This approach had several red flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No guarantees about URL format consistency&lt;/li&gt;
&lt;li&gt;Not an official API endpoint&lt;/li&gt;
&lt;li&gt;Could break without notice&lt;/li&gt;
&lt;li&gt;Not sustainable for a production service&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Back to Basics: OpenStreetMap + Leaflet
&lt;/h2&gt;

&lt;p&gt;Ultimately, I reverted to a more traditional approach using OpenStreetMap with Leaflet. While this solution has its limitations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search functionality isn't as robust as Google Maps&lt;/li&gt;
&lt;li&gt;Less polished UI compared to Google's interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast and responsive&lt;/li&gt;
&lt;li&gt;Highly customizable&lt;/li&gt;
&lt;li&gt;Stable and predictable APIs&lt;/li&gt;
&lt;li&gt;Cost-effective&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building Resilient Systems
&lt;/h2&gt;

&lt;p&gt;Even OpenStreetMap isn't bulletproof. That's why I implemented both solutions - the Google Maps workaround as a backup to the primary OpenStreetMap implementation. This redundancy ensures service continuity if either solution fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;This experience reinforced several important principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Nothing is perfectly stable&lt;/strong&gt; - Build redundancy into your system with multiple fallback options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid dependencies on unofficial APIs&lt;/strong&gt; - Reverse-engineering existing services may seem clever, but it's a maintenance nightmare&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Purpose-built tools often win&lt;/strong&gt; - Sometimes combining developer-focused tools to build custom components is more reliable than trying to hack existing consumer products&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When building production systems, it's tempting to take shortcuts by leveraging popular services in unintended ways. However, the short-term gains often lead to long-term technical debt. Sometimes the boring, stable solution is the right choice.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What mapping solutions have you used in your projects? Have you faced similar trade-offs between familiarity and stability?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>maps</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Standalone Python CLI Distribution Made Simple</title>
      <dc:creator>crimson206</dc:creator>
      <pubDate>Sun, 08 Jun 2025 18:33:22 +0000</pubDate>
      <link>https://dev.to/crimson206/standalone-python-cli-distribution-made-simple-54mm</link>
      <guid>https://dev.to/crimson206/standalone-python-cli-distribution-made-simple-54mm</guid>
      <description>&lt;p&gt;Want to share your Python CLI tool with non-technical users? Let's make it simple - no Python installation required!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Standalone Binaries?
&lt;/h2&gt;

&lt;p&gt;Traditional Python CLI tools depend on the Python environment present during installation. For more reliable service delivery, sometimes we need to distribute a standalone package with Python compiled into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Solution
&lt;/h2&gt;

&lt;p&gt;I've created a template repository that handles all the complexity for you:&lt;br&gt;
&lt;a href="https://github.com/crimson206-templates/python-standalone-binary" rel="noopener noreferrer"&gt;python-standalone-binary&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This template provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple example CLI implementation&lt;/li&gt;
&lt;li&gt;Installation scripts&lt;/li&gt;
&lt;li&gt;Release workflow&lt;/li&gt;
&lt;li&gt;Cross-platform support (Linux, Windows, macOS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these tools, you can easily distribute standalone Python CLI binaries on GitHub using a simple installation command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/&lt;span class="o"&gt;{&lt;/span&gt;user&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;repo&lt;span class="o"&gt;}&lt;/span&gt;/main/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try Our Example
&lt;/h2&gt;

&lt;p&gt;Want to see it in action? Test our example CLI with these commands:&lt;/p&gt;

&lt;h3&gt;
  
  
  Linux / macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/crimson206-templates/python-standalone-binary/main/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows (PowerShell)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://raw.githubusercontent.com/crimson206-templates/python-standalone-binary/main/scripts/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the CLI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux/macOS&lt;/strong&gt;: Simply type &lt;code&gt;example-cli&lt;/code&gt; in your terminal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows&lt;/strong&gt;: The installer will show "Installed to: {path}"

&lt;ul&gt;
&lt;li&gt;Example path: &lt;code&gt;C:\path-to\example-cli.exe&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the shown path in PowerShell&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploying Your Own CLI
&lt;/h2&gt;

&lt;p&gt;The release action is configured to run automatically when version tags are pushed.&lt;/p&gt;

&lt;p&gt;To deploy this example in your own repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   gh repo fork crimson206-templates/python-standalone-binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a release:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;source &lt;/span&gt;scripts/tagging.sh v0.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;After the action completes successfully, test your deployment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="c"&gt;# Linux/macOS&lt;/span&gt;
   curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/&lt;span class="o"&gt;{&lt;/span&gt;user&lt;span class="o"&gt;}&lt;/span&gt;/python-standalone-binary/main/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/crimson206-templates/python-standalone-binary" rel="noopener noreferrer"&gt;Template Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/crimson206-templates/python-standalone-binary#documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/crimson206-templates/python-standalone-binary/tree/main/src/example_cli" rel="noopener noreferrer"&gt;Example Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ready to make your Python CLI more accessible? Check out the &lt;a href="https://github.com/crimson206-templates/python-standalone-binary" rel="noopener noreferrer"&gt;template repository&lt;/a&gt; and start building!&lt;/p&gt;

</description>
      <category>python</category>
      <category>cli</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
