From Source Folders to a Systems Map
Step through onboarding a school district into SystemsCatalog, from setting principles to a map of every system it runs on.
1Establish the principles
Start with the engineering standards your team already agrees on: secrets, error handling, testing, naming and more. They install into Claude Code as a plugin, and each estate sets its own priorities. Claude then applies them whenever it writes or reviews code, and scores every repo against them later on. Click a priority to change it.
CLAUDE.md
## Principle priorities Overrides each principle's default priority for this estate. | Principle | Priority | |---------------------------|----------| | Exception handling | P1 | | Secrets management | P1 | | Committed data privacy | P1 | | Unit testing and mocks | P1 | | Database naming standard | P1 | | Hub data modeling | P1 | | Observability | P2 | | Agent supportability | P2 | | Support handoff | P2 | | Data-driven design | P2 | | Fix at the source | P2 | | UI/UX design | P2 | | Naming conventions | P2 | | Dependency hygiene | P2 | | SOLID | P2 | | SMART | P3 | | SQL formatting standards | P3 |
2Point Claude Code at an app
Open Claude Code in an application's source folder. It doesn't have to be in Git or Azure DevOps. This one is a PowerShell job copied off a file share. Claude reads the code, works out what the app does and what it talks to, and writes the two files every catalogued app carries: README.md for developers and SYSTEMS.md for architects and owners.
--- systems_catalog: app_id: APP-0004 catalog_repo: https://dev.azure.com/your-district/IT/_git/SystemsCatalog --- # BusRoutesExport > Sends the nightly rider file to the bus routing vendor, so each > morning's routes reflect yesterday's enrolment and address changes. ## Purpose & Business Context Routes are planned in the vendor's routing service, which knows nothing about enrolment changes. Each night this job pulls riders from the DataHub and uploads them, so a student who moved or changed schools yesterday is on the right bus today. For ownership, criticality and data flows, see SYSTEMS.md. ## Solution Structure | File | Role | |-----------------------|-----------------------------------------------| | Export-Routes.ps1 | Queries the DataHub, writes and uploads CSV | | RiderQuery.sql | Active students with a bus-eligible address | | config.psd1 | DataHub connection, SFTP host and folder | | BusRoutesExport.xml | Scheduled task: daily at 02:00 | ## Build & Run .\Export-Routes.ps1 -WhatIf # writes riders.csv, skips the upload .\Export-Routes.ps1 # full run, as the scheduled task does ## Runbook If routes look stale in the morning: check the task history, rerun the script by hand, then confirm riders.csv arrived on the vendor SFTP. ## Known Issues & Technical Debt - The SFTP password is hard-coded in Export-Routes.ps1. - A failed upload still exits 0, so the task reports success.
---
human:
app_name: BusRoutesExport
app_id: APP-0004
category: integration
lifecycle_stage: production
business_owner: transportation@harbourview.example # confirm
technical_owner: it-integrations@harbourview.example
vendor: Internal
support_tier: business-hours
criticality: tier-3
business_processes: [student-transportation]
data_classification: confidential
upstream_systems: [APP-0001]
downstream_systems: [APP-0010]
data_flows:
- direction: inbound
peer: APP-0001
method: DB Link
frequency: daily
payload: student addresses, school assignments, bell times
- direction: outbound
peer: APP-0010
method: SFTP
frequency: daily
payload: rider file (CSV)
technical_debt_score: high
repo:
repos:
- name: BusRoutesExport
role: primary # local Git only; push to Azure DevOps
infrastructure:
hosting: On-Prem
environments: [prod]
---
# BusRoutesExport — Systems Catalog Entry
## Purpose in the Enterprise
Keeps student transportation in step with enrolment. If it stops,
routes drift from reality within days: new students are missing and
students who moved are picked up at their old address.
## Where This Fits
- Upstream: APP-0001 DataHub (rider data)
- Downstream: APP-0010 Bus Routing Service (vendor SFTP) 3Measure, audit and fix
The harvester measures the repo: how much business logic it holds, its tests and its tech stack. It writes those numbers into SYSTEMS.md. Then /principles-audit scores the code against the principles from step 1 and lists the gaps in the order to fix them. The audit itself changes no code. Once the gaps are known, a developer can ask Claude to fix them and re-audit, and the score goes up. Try one of the fixes below.
| Principle | Priority | Score | Notes |
|---|---|---|---|
| Secrets management | P1 | 20 | SFTP password in plain text in Export-Routes.ps1 |
| Committed data privacy | P1 | 85 | No student data committed |
| Exception handling | P1 | 40 | A failed upload still exits 0, so the task looks successful |
| Unit testing and mocks | P1 | 0 | No tests |
| Observability | P2 | 30 | No log file or alert when the nightly run fails |
| Support handoff | P2 | 60 | README now covers the schedule and how to rerun |
| Naming conventions | P2 | 80 | Verb-Noun script names |
| Dependency hygiene | P2 | 70 | SFTP module version not pinned |
Overall weighted score: 46 / 100.
Fix order: secrets management → dependency hygiene → exception handling · observability → unit testing and mocks · support handoff
harvested:
repo:
source_branch: main
has_pipeline_yaml: false
size:
logic_lines: 420
test_files: 0
shape_share_pct: 0
complexity: null # lizard does not parse PowerShell Fix the gaps with Claude, then re-audit. The developer asks; Claude changes the code; SystemsCatalog re-scores the repo.
4Repeat for every repo
Do the same for each application the district has built, wherever its source lives: Azure DevOps, GitHub or a file share. Each repo ends up with its own README.md and SYSTEMS.md, sized and scored. Onboard them one at a time or all at once.
| App | Source | README | SYSTEMS | Size | Score | |
|---|---|---|---|---|---|---|
| DataHub | Azure DevOps | · | · | · | · | |
| SisSync | Azure DevOps | · | · | · | · | |
| ParentPortal | GitHub | · | · | · | · | |
| BusRoutesExport | File share | ✓ | ✓ | XS | 46 | |
| FeesExport | Azure DevOps | · | · | · | · | |
| AttendanceKPI | GitHub | · | · | · | · |
5Aggregate into the catalog
The catalog is a repo of its own. It pulls in the SystemsCatalog framework (schema, scripts and templates) and lists where every app repo lives. The SYSTEMS.md files stay in each app's repo, next to the code they describe, so they evolve with it.
# catalog.yml — what regenerate.py needs to know about the estate. catalog_repo_url: https://dev.azure.com/your-district/IT/_git/SystemsCatalog # App repos whose SYSTEMS.md belongs in this catalog, cloned as # siblings of this repo. Off-the-shelf systems live under ootb/. app_repos: - ../DataHub - ../SisSync - ../ParentPortal - ../BusRoutesExport # was a file share; now in Git - ../FeesExport - ../AttendanceKPI
SystemsCatalog/
├── catalog.yml
├── CLAUDE.md
├── INVENTORY.md # generated tables + system diagram
├── SIZING.md # generated sizing + findings
├── framework/ # SystemsCatalog: schema, scripts, templates
└── systems-catalog-starter/
├── ootb/ # off-the-shelf systems (next step)
└── diagrams/ # generated .mmd, .svg and graph.json 6Add off-the-shelf systems
Your SIS, HR system, identity platform, finance system and vendor services have no code of yours, but most data flows start or end in them. Each gets a SYSTEMS.md in the catalog itself, so the map shows the whole estate, not just what you built. Add them one at a time or all at once.
systems-catalog-starter/ootb/student-information-system/SYSTEMS.md
---
human:
app_name: Student Information System
app_id: APP-0007
category: ootb
lifecycle_stage: production
business_owner: student-records@harbourview.example
vendor: SIS vendor (SaaS)
support_tier: 24x7
criticality: tier-1
business_processes: [enrolment, attendance, grading]
data_classification: restricted
downstream_systems: [APP-0002]
data_flows:
- direction: outbound
peer: APP-0002
method: DB Link
frequency: hourly
payload: students, staff, enrolments, attendance
---
# Student Information System — Systems Catalog Entry
The system of record for students. Everything downstream of the
DataHub ultimately starts here. 7Run the inventory
One command gathers every SYSTEMS.md, validates them against the schema and checks every cross-app link. It then draws the dependency diagrams and writes INVENTORY.md and SIZING.md. Run it again whenever anything changes; hand-written findings on those pages are kept.
| App IDCatalog ID, APP-NNNN. Taken in order and never reused. | ApplicationClick a name to open its repository. | CategoryWhat kind of system it is. See the section below. | TierHow much the district depends on it: T1 core, T2 important, T3 supporting. | OwnerThe team accountable for it. | SizeBusiness-logic size, XS to XL. See the SIZING.md tab. — for off-the-shelf systems. | PrinciplesOverall weighted score from /principles-audit, out of 100. |
|---|---|---|---|---|---|---|
| APP-0001 | Data hub | T1 | data-platform | L | 78 | |
| APP-0002 | Integration | T1 | it-integrations | M | 58 | |
| APP-0003 | Custom app | T2 | web-apps | L | 81 | |
| APP-0004 | Integration | T3 | it-integrations | XS | 46 | |
| APP-0005 | Integration | T3 | it-integrations | S | 66 | |
| APP-0006 | Reporting | T2 | data-platform | M | 74 | |
| APP-0007 | Off-the-shelf | T1 | student-records | — | — | |
| APP-0008 | Off-the-shelf | T1 | infrastructure | — | — | |
| APP-0009 | Off-the-shelf | T2 | finance | — | — | |
| APP-0010 | Off-the-shelf | T3 | transportation | — | — | |
| APP-0011 | Off-the-shelf | T2 | human-resources | — | — |
Hover or tap a column heading for a quick explanation, or open the sections below for more.
Tier: what T1, T2 and T3 mean
How much the district depends on the system, from criticality in its SYSTEMS.md. It sets the support level and how fast it must be restored.
- T1, core: an outage stops teaching, safety or pay. 24x7 support, restored within hours.
- T2, important: an outage hurts but has a workaround. Business-hours support.
- T3, supporting: can wait until the next business day.
Category: the five kinds of system
What kind of system it is, which decides how it's supported and where its SYSTEMS.md lives.
- Off-the-shelf: a vendor product with no code of ours, like the SIS or HR system. Its SYSTEMS.md lives in the catalog.
- Custom app: an application the district built, with its own repo.
- Integration: code whose job is moving data between systems: syncs, exports and feeds.
- Data hub: the central store other systems read from, instead of connecting to each other directly.
- Reporting: dashboards and analytics built on the data.
Owner: business and technical owners
The team accountable for the system, so every question has somewhere to go. Each SYSTEMS.md records a business owner, who decides what the system should do, and a technical owner, who keeps it running. The inventory shows the accountable team.
Principles: how the score is weighted
The repo's overall weighted score out of 100 from /principles-audit, as in step 3. P1 principles count three times, P2 twice and P3 once, so a gap in secrets or testing costs more than one in formatting. Off-the-shelf systems show — because there's no code of ours to audit.
| RepoThe app repository. Click a name to open it. | TierT1 core, T2 important, T3 supporting. Read size against tier. | KnowledgeBusiness: rules only the district holds. Functional: general plumbing. Mixed: both. | SizeBand from logic lines: XS, S, M, L, XL. | LogicLines of business logic. Excludes data shapes, tests, generated code, blanks and comments. | ComplexityShare of function code in hard-to-change functions (complexity over 15). — means not measured. | StackLanguages counted. | RuntimeOptional, from support dates you provide. The runtime and its support status: red out of support, amber ends within six months, grey legacy, green supported. Hover a value for dates. | PackagesOptional, from your own package scans. Red: packages with known vulnerabilities. Amber: deprecated. Grey: outdated. Hover a value for the package names. | ShapesLines in data-only classes (models, entities, DTOs), left out of Logic. Hover a value for its share. | CommitsTotal commits on the harvested branch. | 90dCommits in the last 90 days. | TestsTest files, not individual tests. 0 means no tests at all. | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T1 | Business | L | 9,840 | Moderate 5% | SQL · C# | .NET 8.NET 8: support ends 2026-11-10 | 106Vulnerable: Microsoft.Data.SqlClient 5.1.1: security bypass, fixed in 5.1.3 · 6 outdated · Source: dotnet list package | 1,86015.9% of this repo's counted lines are data shapes, left out of Logic. | 1,180 | 64 | 14 | ||
| T2 | Business | L | 7,260 | Low 1% | TypeScript · C# | .NET 9 + Node.js 20.NET 9: support ends 2026-11-10 · Node.js 20: support ended 2026-04-30 | 1014Vulnerable: lodash 4.17.15 (npm): prototype pollution, fixed in 4.17.19 · 14 outdated · Source: dotnet list package · npm audit | 9,40056.4% of this repo's counted lines are data shapes, left out of Logic. | 960 | 141 | 31 | ||
| T2 | Business | M | 4,610 | Moderate 4% | Python · SQL | Python 3.8Python 3.8: support ended 2024-10-07 | 107Vulnerable: requests 2.25.1 (pip): leaks proxy credentials, fixed in 2.31.0 · 7 outdated · Source: pip-audit | —Not split for Python · SQL: only C#, TypeScript, JavaScript and VB are. | 305 | 23 | 9 | ||
| T1 | Mixed | M | 3,420 | High 11% | C# | .NET 6.NET 6: support ended 2024-11-12 | 119Vulnerable: Newtonsoft.Json 12.0.3: denial of service, fixed in 13.0.1 · Deprecated: System.Data.SqlClient 4.8.5: replaced by Microsoft.Data.SqlClient · 9 outdated · Source: dotnet list package | 2,95046.3% of this repo's counted lines are data shapes, left out of Logic. | 412 | 12 | 0 | ||
| T3 | Functional | S | 1,150 | Low 0% | C# | .NET Framework 4.6.1.NET Framework 4.6.1: support ended 2022-04-26 | 104Vulnerable: log4net 2.0.8: XML external entity, fixed in 2.0.10 · 4 outdated · Source: dotnet list package | 38024.8% of this repo's counted lines are data shapes, left out of Logic. | 88 | 0 | 2 | ||
| T3 | Functional | XS | 420 | — | PowerShell | PowerShell 5.1PowerShell 5.1: Windows PowerShell, supported with Windows but frozen; PowerShell 7 is current | 0011 outdated · Source: PowerShell Gallery (Posh-SSH 2.3; 3.x is current) | —Not split for PowerShell: only C#, TypeScript, JavaScript and VB are. | 1 | 1 | 0 |
Hover or tap a column heading or value for a quick explanation, or open the sections below for more. Shaded columns are optional and use data you provide.
Runtime and Packages: optional, from data you provide
These two columns are optional and require you to provide the data. SystemsCatalog doesn't track support dates or scan for vulnerabilities itself. It references what you supply and shows it beside everything else it knows about each app. You provide:
- Runtime support dates: the runtimes your estate uses and when their support ends (.NET, .NET Framework, Node.js, Python, PowerShell), kept as a small file in your catalog repo.
- Package scan results from your own build pipelines, using each stack's tool:
dotnet list package --vulnerable --deprecated --outdatedfor .NET,npm auditfor Node,pip-auditfor Python, and the PowerShell Gallery for modules.
SystemsCatalog then references them: it matches each repo's runtime to your support dates, shows the counts here, raises the findings below, and /principles-audit can score vulnerable packages as a P1 gap so they're fixed first. If you don't provide the data, these columns are simply left out.
How size is measured
Logic counts lines of business logic: the code that decides what happens. Data-shape classes, generated code, tests, build output, vendored libraries, blank lines and comments are all left out, so the number reflects what there is to support.
Units aren't strictly comparable. A SQL line, a C# line and a PowerShell line measure different things, so read the ranking as an order of magnitude.
Size and complexity bands
- Size from logic lines: XS under 500 · S 500–2,000 · M 2,000–6,000 · L 6,000–12,000 · XL over 12,000.
- Complexity is the share of function code sitting in functions with cyclomatic complexity over 15, the hard-to-change hotspots: Low under 2% · Moderate 2–8% · High 8–20% · Very High over 20%. — means not measured; the analyser can't parse SQL or PowerShell.
Size and complexity are independent. A small app with High complexity can be harder to change than a large simple one.
Knowledge: business, functional or mixed
- Business: rules only the district holds, such as data models, eligibility and fee policy. Lose the person, lose the knowledge.
- Functional: plumbing found in every IT estate: syncs, SFTP, scheduling, retries. Hirable, and a candidate for consolidation.
- Mixed: both. Staff it as business, tool it as functional.
Shapes: code that holds data but does nothing
Lines in data-only classes: models, entities, DTOs and view models, found by folder or file name. They make a codebase longer without adding behaviour, so they're counted here instead of in Logic. A high share means the app is smaller to support than its raw size suggests.
The split applies to C#, TypeScript, JavaScript and VB only. SQL is counted whole, because in a database repo the schema is the deliverable.
Commits and 90d: is anyone working on it?
Commits is the total on the harvested branch, and 90d the number in the last 90 days. A tier-1 app with no recent commits may be stable, or may have no one left who knows it. Both count only the branch that was checked out when the repo was harvested.
Tests: test files, not test counts
The number of test files: files in a folder ending in test, tests or spec, or with test or spec in the name. 0 means no tests at all. Three files could hold 200 tests or almost none, so this shows whether testing exists, not how good it is. Test quality is scored by /principles-audit under "Unit testing and mocks".
What the sizing exposed
- 1 of 6 repos had no source control. BusRoutesExport lived on a file share until onboarding.
- 2 of 6 repos have P1 security or privacy gaps. BusRoutesExport has a plain-text SFTP password, and FeesExport has real student names in a committed sample file. Fix these first.
- SisSync is tier-1, High complexity and has no tests. Every hotspot in it is a change nobody can verify.
- ParentPortal is smaller than it looks. 56.4% of its code is data shapes, so its 7,260 logic lines, not the raw total, are the real support load.
- Optional · your data 5 of 6 repos run on a runtime that is out of support or ends within six months. Out of support: SisSync (.NET 6), ParentPortal (Node.js 20), FeesExport (.NET Framework 4.6.1), AttendanceKPI (Python 3.8). Ending soon: DataHub (.NET 8, 2026-11-10), ParentPortal (.NET 9, 2026-11-10). 5 repos use packages with known vulnerabilities.
- 1,570 lines of functional plumbing across 2 small exports. This code is general-market skill rather than district knowledge, and a candidate to consolidate onto one integration platform.
8Explore the map
The result is one map of how the district actually runs. Click any system to see who owns it, how big it is and what depends on it, or try one of the questions below. These used to take a meeting to answer.
What you just saw
A fictional district with six in-house applications and five off-the-shelf systems goes from scattered source folders to one validated, queryable map. The steps are the same ones we follow with real districts:
- Agree on the principles your code should follow, and set your own priorities.
- Point Claude Code at each application, wherever its source lives: Azure DevOps, GitHub, or a folder on a file share. It writes a
README.mdfor developers and aSYSTEMS.mdfor architects and owners. - Measure, audit and fix each repo: how much business logic it holds and how it scores against your principles. Developers then ask Claude to close the gaps, such as writing the missing unit tests, and the re-audit shows the score rise.
- Aggregate the repos into one catalog, and add the off-the-shelf systems your data flows through.
- Run the inventory to validate everything and generate the diagrams,
INVENTORY.mdandSIZING.md. - Ask the catalog questions: what breaks if this system goes down, who owns everything that touches student data.
What onboarding surfaces
Most estates turn up something on day one: an integration that only exists on a file share, a password committed to a script, real student data in a sample file, or a critical sync with no tests. Finding those is part of the value. Each one lands in the catalog as a finding with an owner, in the order it should be fixed.
Who it’s for
CIOs and IT leaders who need to know what they run, who owns it and what depends on it, without relying on the memory of one or two long-serving staff.
Ready to Make More Room for Learning?
With offices in Calgary, AB; Desert Hot Springs, CA; and Brooksville, FL, we serve schools, districts and educational organizations across North America. Let's talk about where you are and where you want to go.
Contact Us