Organize your code the way your company works
Contents
Determining how to organize your code across repositories is one of the most fundamental decisions you’ll make, but it’s seemingly one of the least deliberate. Repositories get created when projects start, named for whatever needed them at the time, and dropped into whatever grouping made sense that week. The company reorganizes, but the repositories rarely follow.
Part of the reason is that source control management tools were never designed to model how your business is organized. GitHub organizations are a flat set of repositories, GitLab’s groups nest but still live inside a single instance, and the moment your code spans two GitHub orgs, GitHub alongside GitLab, or a handful of instances inherited through acquisitions, no single place describes the whole estate. Each tool knows its own corner, but none of them knows the shape of your company.
And that shape is exactly what you need to measure and manage large, complex codebases. How exposed is the payments platform to this CVE? How far along is retail banking on the Java 25 migration? Which repositories should an agent touch when you hand it that migration to run? Those questions come in terms of app portfolios, business units, and teams. When you group the estate the way the business runs, change becomes something you can see, measure, and steer more effectively.
Mapping business-focused orgs on top of repos
Moderne’s organizational structure lets you draw those lines yourself. It sits on top of however your repositories are physically laid out and across whatever SCM tools hold them, so you can impose logical, overlapping views to match how work is scoped or however your company is organized. Once those views exist, every operation you run can point at one of them.
The structure is defined in a file called repos.csv. At its simplest, the file is a list of repositories, with the columns Moderne needs to find and identify each one: the clone URL, the branch, the origin, and the path. The hierarchy comes from a set of optional organization columns named org1, org2, org3, and so on, with no fixed limit on how many levels you define. Each row places its repository into a chain of organizations, with those on the left as children of the ones on their right. So a repository assigned Team 1, Director A, ALL is read as Team 1 nested under Director A nested under the top-level org. The same repository can appear in more than one row, so a single service can belong to several distinct organizations at once.
cloneUrl,branch,origin,path,org1,org2,org3
https://github.com/acme/payments-api,main,github.com,acme/payments-api,Payments,Director A,ALL
https://gitlab.acme.com/core/ledger-core,main,gitlab.acme.com,core/ledger-core,Ledger,Director A,ALL
https://github.com/acme/payments-api,main,github.com,acme/payments-api,Spring Boot 2,Migrations,ALLUsing the example, you can read the org columns right to left to understand the hierarchy. Everything rolls up to ALL, Director A owns both Payments and Ledger, and payments-api appears a second time because it also belongs to a Spring Boot 2 cohort under a cross-cutting Migrations program.
Notice that the ledger repository lives on a different SCM server. In this case it’s a self-managed GitLab instance, while the rest are on GitHub. This is part of the power of Moderne organizations that no single SCM has. Because each row names its own clone URL and origin, and the organization columns are assigned independently of where a repository is hosted, one Moderne organization can group repositories that sit in different GitHub organizations, on GitHub and GitLab at once, or across several instances of both. The hierarchy is built on top of your code wherever it lives, so the estate has a single description that isn’t limited by the structure defined per tool.
Designing an operational hierarchy
It’s tempting to just drop in a flat list and get going, but it’s worth spending a little time on the hierarchy before you lock it in. Go through your repositories and ask how they actually group, by who owns what and by which ones work together. Even if the result turns out to be mostly a flat structure, the exercise pays off because it means you actively choose how your code is organized. A deeper hierarchy lets you scope more specifically, so a search, recipe, or report hits just the repositories that matter instead of running over all of them. The goal is enough structure to scope cleanly, without going so far that the hierarchy becomes more trouble to maintain than it is worth.
You can even store any metadata you may want to associate with each repository in the repos.csv. That’s because any column Moderne does not recognize is simply ignored. You can carry team names, owners, cost centers, or ticket references alongside the rows, and Moderne reads past them while you can have your own tooling to read them directly.
So every row in repos.csv carries up to three kinds of information:
- Identity:
cloneUrl,branch,origin, andpathtell Moderne how to find and check out the repository. - Hierarchy:
org1,org2,org3, and beyond, with children on the left, place the repository into one or more organizations. - Your own metadata: any other column is ignored by Moderne and free for team names, owners, or other tracking information.
Build your own working set
You might assume this structure must be defined once and then applied to everyone, and that is indeed one way to use it. In that case, an administrator or platform team determines the hierarchy and configures it centrally for all users. A repos.csv provided to the Moderne Connector becomes the organization hierarchy the whole tenant works from. This is the right place for stable groupings like teams, departments, and the company roll-up.
But you can also build a custom grouping to use with the CLI by writing your own repos.csv. This can be as simple as a list of clone URLs of just the repositories you care about. Additionally, the platform allows you to create user-configured organizations by selecting the repositories you want and saving them to your account. Either of these options let you customize your own organizations, but which route to go depends on who needs to use the particular set of repositories and for how long.
A user organization is private to you, so nobody else on your team can see it. This makes it safe to spin one up for a single task, like a migration cohort, a one-off investigation, or a demo, and stop thinking about it afterward. If you prefer to share it with teammates, it’s as simple as sharing a repos.csv. Hand someone your file and they have the same repositories to work from. The CLI also produces a repos-lock.csv that pins the exact state of your setup, the branches, the commit SHAs, and the locations of prebuilt LSTs, so a teammate reproduces your environment exactly from one file instead of rebuilding it. Put that lock file somewhere central and the whole team can point at the same reference so everyone in your group is working from the same set of repositories rather than depending on what’s configured centrally.
So not only is the organization model flexible in its ability to group many repositories together, it’s even flexible in the consumption of those groups:
- Personal: a
repos.csvyou use locally with the CLI, or a private user-configured organization in the platform. - Shared with teammates: a
repos.csv(orrepos-lock.csv) you pass along, so others work from the same repositories and, with the lock file, the same exact setup. - Tenant-wide: the organization hierarchy an administrator configures centrally from a
repos.csv, which everyone in the platform works from.
Operating your codebase at all levels
The reason any of this matters is that the structure is for more than just navigation. Whatever areas you have defined become the scope that every operation runs against. Whether you are searching the code, transforming it yourself, or pointing an agent at it, the operation stays within that selection. You pick the organization, run what you need, and the results come back for that group of repositories and nothing else. Change the selection and the same search or recipe now answers the same question about a different part of the estate.
Every part of the platform reflects the same hierarchy, including DevCenter, Changelog, and Moddy. Whatever you select, the platform narrows the scope to only that organization, so you can look at a single team’s DevCenter dashboard, your whole group’s Changelog, or search the entire estate in Moddy just by changing the organization selection.
The CLI carries the same idea onto your local file system. When you sync an organization locally, the CLI lays your repositories out in a directory tree that mirrors the org hierarchy:
$ mod git sync csv working-set repos.csv└── ALL
└── Director A
├── Payments
│ ├── payments-api
│ └── payments-ledger
└── Ledger
└── ledger-coreCommands like mod run, mod study, and mod devcenter then respect where you are in that tree. If you run a command from the root, it works across everything beneath it. When you change into a sub-organization’s directory first and run the same command, it narrows to just that branch, producing outputs recursively for each org and sub-org below the level you ran it from.
Running change across the organization
A migration across thousands of repositories is a real coordination problem. You have to track how far along it is, the work has to reach the teams that own the code, and it rarely can happen everywhere at once. With an organizational structure that mirrors the way your business runs, you can tackle all three.
No matter where you sit in your organization, you decide how to divide up the work without losing sight of it, and you see the version of the picture that fits your role. Developer teams can apply, test, and commit changes across the many repositories they own all at once, or point an agent at their organization and have it run the change across only those repositories. Team leads use DevCenter on their own organization to see the status of only their repositories, and Directors can look a level up from that to see all of their teams rolled up together. It is the same underlying data, read and operated on at whatever height in the tree is relevant to you.
The structure also does not have to follow the org chart. You can group repositories into waves and run and measure the rollout one wave at a time. Use a first cohort to prove the change out or sequence the change based on dependency maps. A migration that would be overwhelming as a single push becomes a sequence you can plan, staff, and report on.
Every repository, everywhere, all at once
Your code stays exactly where it is, in the same GitHub and GitLab instances. What sits on top of it now is a description of the estate that matches how your company actually works, and everything you do in Moderne reads from that description. The structure that used to accumulate on its own becomes something you decide, and the part of your estate you care about becomes something you can name and point at instead of assembling by hand every time.
This matters even more as agents enter the picture. The same scoped view also bounds what an agent sees and acts on, so agentic work stays inside the part of the estate you point it at instead of running loose over the whole thing. And when an agent changes a lot of code across a lot of places, the same structure scopes the review, so you can check what happened in the organization you own instead of combing through everything it touched.
Define it once, and your searches, recipes, commits, dashboards, and change history all work from it. So much of the manual effort your team spends rounding up the right repositories is really just the absence of a structure like this. Imagine how much of it disappears once you have one.


