โš™๏ธ Engineering

๐Ÿ—๏ธ Building an Org Monorepo

๐Ÿ’ก An org monorepo is not โ€œone giant Git tree.โ€ It is a versioned dependency graph with enforceable import edges, a single toolchain contract, reusable CI/CD templates, and IaC that ships next to the code it provisions. Below is the blueprint we use.

๐Ÿ˜ตโ€๐Ÿ’ซ Why polyrepos rot under shared code

Most platform teams rediscover the same failure modes once shared Python code shows up across services:

  • ๐Ÿ” Library updates require sequential PRs across producer + consumer repos, plus an internal package index bump โ€” merge the lib, wait for the wheel to publish, then bump the consumer.
  • ๐Ÿงช You cannot cheaply prove a lib change is safe against the full dependent closure; nobody runs โ€œevery serviceโ€™s testsโ€ before merging.
  • ๐Ÿ“‹ Engineers stop extracting libraries and start copy-pasting, because sharing is too expensive.
  • ๐ŸŒ€ Accidental cycles and fuzzy ownership appear the moment โ€œshared helpersโ€ leak between services inside a junk-drawer repo.
  • ๐Ÿ”Ž Cross-repo search and IDE navigation are worse than a single workspace checkout.
  • ๐Ÿงญ Per-repo lint/format/type configs diverge until cross-repo contribution becomes a tax.

Our monorepo collapses publish-then-consume into path / editable installs via uv workspaces [2]. CI expands the affected closure from the workspace graph / uv.lock. The invariant: internal packages are linked, not version-chased. External consumers outside the monorepo can still get versioned wheels from an internal index if needed โ€” but inside the repo, path deps are law.

๐Ÿ“ Target topology

Keep top-level directories semantic and mutually exclusive. Every leaf package owns a pyproject.toml and a CI entrypoint: .gitlab-ci.yml on GitLab, or the GitHub equivalent (a thin leaf workflow / config that uses: a reusable workflow โ€” details below). Nothing cross-cuts via relative imports into another leafโ€™s src/.

๐Ÿ” VCS exclusivity: an org standardizes on either GitHub or GitLab โ€” never both as first-class homes for the same monorepo. Keep exactly one of .github/ or .gitlab/ for shared templates, child-pipeline / reusable-workflow entrypoints, and ownership metadata.

org-monorepo/
โ”œโ”€โ”€ .github/                 # XOR: workflows/, actions/, CODEOWNERS
โ”‚   # โ€” or โ€”
โ”œโ”€โ”€ .gitlab/                 # XOR: ci/ templates, includes, CODEOWNERS
โ”œโ”€โ”€ apps/                    # user-facing / operator-facing applications
โ”œโ”€โ”€ libs/                    # shared abstractions (org-namespaced packages)
โ”œโ”€โ”€ projects/                # domain-bounded workspaces (ETL, ML, batch, research)
โ”œโ”€โ”€ services/                # independently deployable microservices
โ”œโ”€โ”€ dockers/                 # shared Dockerfiles, base images, compose stacks
โ”œโ”€โ”€ cookiecutters/           # templates for poe new-* scaffolds (apps, libs, โ€ฆ)
โ”œโ”€โ”€ iac/                     # Terraform / Pulumi / cloud foundation modules
โ”œโ”€โ”€ docs/                    # docs portal / landing โ€” aggregates leaf docs via CD
โ”œโ”€โ”€ pyproject.toml           # uv workspace root + shared tool config
โ”œโ”€โ”€ uv.lock                  # deterministic resolver output
โ””โ”€โ”€ README.md

๐Ÿ”Ž Directory contracts

  • ๐Ÿš€ apps/ โ€” deployable application binaries / UIs / CLIs with a release artifact. May depend on libs/*. Must not import services/* or sibling apps.
  • ๐Ÿ“ฆ libs/ โ€” the only approved sharing layer. Logging, auth clients, protobuf stubs, feature flags, schema helpers, ML feature transforms โ€” anything with a stable public API and tests. Naming is org-namespaced (see below).
  • ๐Ÿงฌ projects/ โ€” domain-centric workspaces (e.g. projects/risk-scoring, projects/claims-etl). These are not microservices; they are bounded contexts that may produce jobs, notebooks (exported), or training pipelines. Depend on libs/*, never on apps/*.
  • ๐Ÿ›ฐ๏ธ services/ โ€” network-facing microservices (HTTP/gRPC/workers) with their own image + deploy pipeline. Import only from libs/*. Prefer building FROM shared bases in dockers/ rather than copy-pasting Dockerfiles.
  • ๐Ÿณ dockers/ โ€” shared container assets: org base images, common Dockerfiles, multi-stage templates, and local compose stacks (deps, mesh stubs). Leaves reference these; they do not reinvent FROM python:โ€ฆ in every app/service. Image build/push CD still runs from the leaf that owns the final artifact, using dockers/ as build context / FROM source.
  • ๐Ÿช cookiecutters/ โ€” golden-path templates for new leaves (python-lib, python-service, js-app, โ€ฆ). Downstream engineers scaffold via task-runner CLIs (poe new-python-lib, poe new-js-app) โ€” they should not need to learn the nuts and bolts of workspace wiring, CI stubs, or naming maps. See the Cookiecutters section.
  • โ˜๏ธ iac/ โ€” Terraform (or equivalent) modules and live stacks. App/service code does not import IaC; CI wires plan/apply via path filters.
  • ๐Ÿ“š docs/ โ€” the docs portal landing page and shared chrome (nav, style, ADRs, org-wide guides). Downstream leaves own their own docs/ nodes; CD builds them on the fly and publishes one site. See the Docs section.
  • ๐Ÿงฉ .github/ or .gitlab/ โ€” shared templates + the parent pipelines that fan out into leaf jobs (child pipelines / reusable workflows). See CI section.

๐Ÿงพ What every leaf owns

A leaf is not โ€œjust source.โ€ It ships its package manifest and its CI contract:

# GitLab leaf
libs/foo-bar-baz-qux/
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ .gitlab-ci.yml           # child-pipeline entry (thin; includes shared template)
โ”œโ”€โ”€ docs/                    # leaf docs node (API + how-to) โ€” aggregated by CD
โ”œโ”€โ”€ src/foo/bar/baz/qux/
โ””โ”€โ”€ tests/

# GitHub leaf โ€” Actions workflows must live under repo-root .github/workflows/
# so the leaf owns a thin config; the stub workflow lives next to shared templates
libs/foo-bar-baz-qux/
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ ci.yml                   # leaf values: image, matrix, deploy target, โ€ฆ
โ”œโ”€โ”€ docs/                    # leaf docs node โ€” aggregated by CD
โ”œโ”€โ”€ src/foo/bar/baz/qux/
โ””โ”€โ”€ tests/

.github/workflows/
โ”œโ”€โ”€ _python-leaf.yml         # reusable workflow (workflow_call) โ€” the real jobs
โ””โ”€โ”€ libs-foo-bar-baz-qux.yml # stub: path filters + uses: _python-leaf.yml

GitHubโ€™s equivalent of a per-directory .gitlab-ci.yml is not a nested workflow file inside libs/โ€ฆ (Actions only loads workflows from .github/workflows/ at the repo root). The practical equivalent is: leaf ci.yml (values) + root stub workflow that uses: a reusable workflow. Same idea as GitLab โ€” leaf declares intent; shared template owns mechanics.

๐Ÿท๏ธ Lib naming: hyphenated distro โ†’ nested import path

Library distribution names are org-based namespaces written with hyphens. Hyphens map 1:1 to nested packages on disk and in site-packages after install:

# distribution / directory name          โ†’  import / site-packages path
foo-bar-baz-qux                          โ†’  foo/bar/baz/qux
acme-ml-features-transforms              โ†’  acme/ml/features/transforms
acme-platform-logging                    โ†’  acme/platform/logging

Source layout inside the leaf (CI files shown above):

libs/foo-bar-baz-qux/
โ”œโ”€โ”€ pyproject.toml          # name = "foo-bar-baz-qux"
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ foo/
โ”‚       โ””โ”€โ”€ bar/
โ”‚           โ””โ”€โ”€ baz/
โ”‚               โ””โ”€โ”€ qux/
โ”‚                   โ”œโ”€โ”€ __init__.py
โ”‚                   โ””โ”€โ”€ ...
โ””โ”€โ”€ tests/

After uv sync / pip install, the package lands as nested modules under site-packages:

site-packages/
โ””โ”€โ”€ foo/
    โ””โ”€โ”€ bar/
        โ””โ”€โ”€ baz/
            โ””โ”€โ”€ qux/
                โ”œโ”€โ”€ __init__.py
                โ””โ”€โ”€ ...

# consumers import the namespace path, not the hyphenated distro name
from foo.bar.baz.qux import SomeType

Why this matters:

  • ๐Ÿงญ Collision resistance โ€” org prefixes (acme-โ€ฆ, foo-โ€ฆ) keep internal libs from clobbering top-level PyPI names in site-packages.
  • ๐Ÿ“‚ Discoverability โ€” related libs cluster under the same tree (acme/ml/โ€ฆ, acme/platform/โ€ฆ) in both the repo and the installed environment.
  • ๐Ÿ”— Stable mental model โ€” libs/<distro> โ†” src/<slash-path> โ†” from <dot-path> import โ€ฆ is mechanical: replace - with / (or . for imports).

Hard rules: distribution name is always hyphenated kebab-case; Python packages never use hyphens; do not publish a flat foobarbazqux module that ignores the namespace map.

๐Ÿ“Š Logical layers and allowed dependency edges
flowchart TB
  subgraph consumers["Consumers"]
    A["๐Ÿš€ apps/*"]
    P["๐Ÿงฌ projects/*"]
    S["๐Ÿ›ฐ๏ธ services/*"]
  end

  L["๐Ÿ“ฆ libs/*\norg-namespaced"]
  Dk["๐Ÿณ dockers/*\nbase images / compose"]
  Cc["๐Ÿช cookiecutters/*\npoe new-* templates"]
  D["๐Ÿ“š docs/*"]
  I["โ˜๏ธ iac/*\nTerraform / cloud"]
  CI["๐Ÿงฉ .github XOR .gitlab\nCI + CODEOWNERS"]

  A --> L
  P --> L
  S --> L
  A -->|FROM / build context| Dk
  S -->|FROM / build context| Dk
  Cc -.->|scaffolds| A
  Cc -.->|scaffolds| L
  Cc -.->|scaffolds| S
  Cc -.->|scaffolds| P
  A -.->|path filters / deploy| CI
  S -.->|path filters / deploy| CI
  Dk -.->|rebuild bases| CI
  I -.->|plan/apply| CI
  D -.->|docs-only path filter| CI

  A -.->|forbidden| S
  S -.->|forbidden| A
  P -.->|forbidden| A
  L -.->|forbidden| A
            

๐Ÿงฑ Import DAG rules (non-negotiable)

  • โœ… apps|projects|services โ†’ libs
  • โœ… libs โ†’ libs only via an acyclic internal graph (enforce with import-linter / custom ruff plugin / CI graph check).
  • ๐Ÿšซ libs โ†’ apps|projects|services
  • ๐Ÿšซ apps โ†” services (talk over APIs / events, not Python imports)
  • ๐Ÿšซ deep imports into another packageโ€™s private modules โ€” public entry points only

Hard organizational rule: apps/*, projects/*, and services/* never import each other. If two leaves need the same code, it graduates into libs/. Encode that in tooling (import-linter / CI graph check), not wiki pages.

๐Ÿ” Affected-test expansion when a lib changes
flowchart LR
  PR["PR diff"] --> Diff["changed paths"]
  Diff --> Lib["libs/foo-bar-baz-qux\nchanged?"]
  Lib -->|yes| Closure["resolve dependents\nvia uv.lock / workspace graph"]
  Closure --> T1["test libs/foo-bar-other"]
  Closure --> T2["test services/billing"]
  Closure --> T3["test apps/console"]
  Lib -->|no| Local["test only touched leaves"]
            

๐Ÿงฐ Base toolchain (Python)

Standardize the developer loop on a fast resolver, one task runner, strict static analysis, and multi-env tox. Every tool below should be pinned in the workspace root and invoked through poe so humans and CI share identical entrypoints.

โšก uv [2]

Package/project manager + workspace linker. Use uv sync --locked at the root, path deps for libs/*, and uv.lock as the source of truth for affected-package computation. Constraint solving + lockfiles keep local, CI, and prod on the same graph โ€” with materially better cold-install performance than older Poetry-era stacks.

๐Ÿงน Ruff [3]

Single-binary lint + format. Configure once at the workspace root ([tool.ruff]); leaf packages may only tighten, never invent incompatible dialects. Wire it as poe format / ruff check inside poe check.

๐Ÿง  Type checking โ€” mypy [4] or Pyright [5]

Pick one org-wide and enforce disallow_untyped_defs (mypy) or typeCheckingMode = "strict" (Pyright) on libs/* first. Apps and services can ratchet up afterward. Expose the chosen checker as poe mypy (or poe pyright); Pyright is the better fit if you want language-server parity with VS Code / Pylance.

๐ŸŽญ Poe the Poet [6]

Task runner declared in pyproject.toml. This is the control plane: format, check, test, tox, build, codegen, etc. Engineers learn poe check && poe test; CI calls the same tasks via [tool.poe.tasks].

๐Ÿงช tox + tox-uv [7] [8]

Matrix execution across Python versions / factor envs without hand-rolled shell. With tox-uv, envs resolve through uv so local and CI stay aligned. Expose as poe tox.

๐Ÿ› ๏ธ Canonical local / CI developer loop
flowchart LR
  Dev["engineer"] --> Poe["poe check / test / tox"]
  Poe --> UV["uv sync --locked"]
  Poe --> Ruff["ruff format + check"]
  Poe --> Types["mypy | pyright"]
  Poe --> PyTest["pytest + coverage"]
  Poe --> Tox["tox ยท multi-Py"]
  CI["GitHub Actions XOR GitLab CI"] --> Poe
            
# root pyproject.toml โ€” illustrative shape
[tool.uv.workspace]
members = ["apps/*", "libs/*", "projects/*", "services/*"]

[tool.poe.tasks.format]
cmd = "ruff format ."

[tool.poe.tasks.check]
sequence = [
  { cmd = "poe format --check" },
  { cmd = "ruff check ." },
  { cmd = "poe mypy" },
]

[tool.poe.tasks.test]
cmd = "pytest -q"

[tool.poe.tasks.tox]
cmd = "tox"

๐Ÿงฉ CI/CD โ€” parent templates, child nodes where jobs start

Pick one forge and commit to it. The root .github/ or .gitlab/ tree is the parent: shared job definitions, images, rules, and deploy primitives. Leaf CI files are child nodes โ€” thin entrypoints that start the real jobs by including / calling those templates. Do not copy-paste a full pipeline into every leaf.

๐ŸฆŠ GitLab โ€” .gitlab/ + per-leaf .gitlab-ci.yml

.gitlab/
โ”œโ”€โ”€ ci/
โ”‚   โ”œโ”€โ”€ python-leaf.yml      # shared jobs: lint, typecheck, test, build
โ”‚   โ”œโ”€โ”€ docker-deploy.yml    # shared deploy jobs for apps/services
โ”‚   โ””โ”€โ”€ iac-plan-apply.yml
โ””โ”€โ”€ CODEOWNERS

# root .gitlab-ci.yml โ€” parent pipeline / dispatcher
include:
  - local: .gitlab/ci/python-leaf.yml   # optional defaults
stages: [detect, test, build, deploy]

# fan-out: trigger a child pipeline per affected leaf
trigger-libs-foo-bar-baz-qux:
  stage: test
  trigger:
    include:
      - local: libs/foo-bar-baz-qux/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - libs/foo-bar-baz-qux/**/*
        - libs/foo-bar-*/**/*          # or compute dependents from uv.lock

Each leafโ€™s .gitlab-ci.yml stays tiny โ€” it includes .gitlab/ci/python-leaf.yml and only overrides variables (image, pytest path, whether to publish a wheel). Jobs start in the child pipeline for that leaf, not as a 500-line monolith at the repo root.

๐Ÿ™ GitHub โ€” .github/workflows/ reusable workflows

GitHub Actions does not discover workflow YAML inside apps/ or libs/. Workflows live under .github/workflows/. The equivalent of GitLab child pipelines is reusable workflows (on: workflow_call) plus per-leaf stub workflows (or one dispatcher workflow) that pass leaf inputs:

.github/
โ”œโ”€โ”€ workflows/
โ”‚   โ”œโ”€โ”€ _python-leaf.yml           # reusable: the jobs (lint/test/build)
โ”‚   โ”œโ”€โ”€ _docker-deploy.yml         # reusable: build/push/deploy
โ”‚   โ”œโ”€โ”€ libs-foo-bar-baz-qux.yml   # child node / stub โ€” where this leaf starts
โ”‚   โ””โ”€โ”€ monorepo-dispatch.yml      # optional: path-filter โ†’ matrix of stubs
โ”œโ”€โ”€ actions/                       # optional composite actions
โ””โ”€โ”€ CODEOWNERS

# libs-foo-bar-baz-qux.yml (stub โ€” child node)
name: libs/foo-bar-baz-qux
on:
  pull_request:
    paths: ["libs/foo-bar-baz-qux/**", "libs/**/pyproject.toml"]
  push:
    paths: ["libs/foo-bar-baz-qux/**"]
jobs:
  python:
    uses: ./.github/workflows/_python-leaf.yml
    with:
      working-directory: libs/foo-bar-baz-qux
      # or read libs/foo-bar-baz-qux/ci.yml inside the reusable workflow

So: reusable workflow = shared job body; stub workflow (or dispatcher matrix entry) = child node where that leafโ€™s jobs start. Leaf-local ci.yml holds values only โ€” image, matrix, deploy target, Slack channel, โ€œneeds DB?โ€, etc.

๐Ÿงฉ Parent templates โ†’ child nodes โ†’ jobs
flowchart TB
  PR["PR / push"] --> Parent["Parent dispatcher\n.github XOR .gitlab"]
  Parent --> Detect["detect affected leaves\npaths + uv.lock graph"]
  Detect --> C1["Child: libs/foo-bar-baz-qux\n.gitlab-ci.yml / stub workflow"]
  Detect --> C2["Child: services/billing\n.gitlab-ci.yml / stub workflow"]
  Detect --> C3["Child: iac/stacks/...\nplan jobs"]
  C1 --> Jobs1["lint ยท types ยท test"]
  C2 --> Jobs2["lint ยท types ยท test ยท image ยท deploy"]
  C3 --> Jobs3["terraform plan / apply"]
  T["Shared templates\n.gitlab/ci/* or\n.github/workflows/_*.yml"] -.-> C1
  T -.-> C2
  T -.-> C3
            

Always parameterize the same four concerns:

  • ๐ŸŽฏ path filters โ†’ which leafโ€™s child node wakes up
  • ๐Ÿ•ธ๏ธ workspace graph โ†’ which dependents must re-test
  • ๐Ÿณ image build + push for apps/* / services/* on leaf changes; rebuild shared bases under dockers/ when those Dockerfiles change, then rebuild dependents
  • โ˜๏ธ iac/* โ†’ terraform plan on PR, apply on protected branches

๐Ÿ’“ Repo-Health โ€” if you donโ€™t measure it, you canโ€™t improve it

A monorepo without measurable quality is just a bigger place to hide regressions. Unit tests, integration tests, version/arch matrices, and repo-wide coverage are how you prove that a change to libs/* is safe for every downstream apps/, projects/, and services/ consumer โ€” not hope.

๐Ÿงช Unit + integration tests with pytest

Standardize on pytest [29] in every Python leaf:

  • ๐Ÿ”ฌ Unit tests โ€” fast, no network, live next to the package (tests/unit/). Required on every PR child pipeline.
  • ๐Ÿ”— Integration tests โ€” tests/integration/ against realistic boundaries (Testcontainers, compose from dockers/compose/, LocalStack, ephemeral DBs). Mark with @pytest.mark.integration; run on PR for touched leaves, and more broadly on a schedule.
  • ๐Ÿ“ฆ Libs especially โ€” a libraryโ€™s unit suite is necessary but not sufficient. Prefer contract / consumer-style tests that exercise the public API the way apps/* and services/* will call it.
# every Python leaf
libs/foo-bar-baz-qux/
โ”œโ”€โ”€ src/foo/bar/baz/qux/
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ unit/
โ”‚   โ””โ”€โ”€ integration/
โ””โ”€โ”€ pyproject.toml          # pytest + pytest-cov config

๐Ÿ tox matrices โ€” guarantee downstream runtimes

Downstream leaves will not all pin the same Python patch or CPU arch. Use tox (+ tox-uv) so each libs/* (and critical services) proves itself across the matrix your org actually runs:

# libs/foo-bar-baz-qux/tox.ini  (illustrative)
[tox]
env_list = py310, py311, py312, py313

[testenv]
runner = uv-venv-lock-runner
commands =
    pytest tests/unit -q --cov=foo.bar.baz.qux --cov-report=xml

# optional factors โ€” OS / arch via CI matrix, not only tox envs
# e.g. GitHub: strategy.matrix = { python: [...], os: [ubuntu, macos] }
  • ๐Ÿงฉ PR path โ€” affected leaf runs poe test (current default Python) + a lean tox subset if the leaf is a shared lib.
  • ๐ŸŒ Full matrix โ€” poe tox on shared libs/* for every supported CPython, and CI runners for arch/OS (amd64 / arm64, linux / macos) when you ship wheels or multi-arch images.
  • ๐Ÿ›ก๏ธ Why this matters โ€” when services/billing is on 3.11-arm64 and apps/console is on 3.12-amd64, a green single-env lib PR is a lie. The matrix is how you make downstream use guaranteed, not assumed.

๐ŸŒ™ Nightly: crawl the monorepo, accumulate coverage

PR CI proves the diff. Nightly proves the estate. Schedule a parent pipeline (GitHub schedule / GitLab pipeline schedule) that:

  1. ๐Ÿ•ท๏ธ Crawls every testable leaf under apps/*, libs/*, projects/*, services/* (discover pyproject.toml / tox.ini / package.json, etc.).
  2. ๐Ÿงช Runs unit (+ optional integration) suites per leaf โ€” Python via poe test / tox, other languages via their leaf task.
  3. ๐Ÿ“Š Emits per-leaf coverage artifacts (coverage.xml, lcov, โ€ฆ).
  4. ๐Ÿงฎ Accumulates into a monorepo rollup (e.g. merge coverage.py data with coverage combine, or upload all partials to Codecov/Coveralls/Sonar with a monorepo flag).
  5. ๐Ÿ“ˆ Publishes a trend: total %, per-top-level-dir %, worst leaves, and a diff vs. last night โ€” fail the nightly (alert; donโ€™t block product merges) if coverage drops beyond a threshold.
# conceptual nightly (forge-agnostic)
discover leaves
for leaf in leaves:
    (cd $leaf && poe test --cov)   # or poe tox on libs
upload partial coverage artifacts
coverage combine ./coverage-partials/*   # or vendor uploader
publish report โ†’ docs portal / coverage dashboard
route anomalies โ†’ CODEOWNERS for failing leaves
๐Ÿ’“ PR proves the diff; nightly proves the estate and pages the owners
flowchart TB
  PR["PR / MR"] --> Aff["affected leaves\n+ dependents"]
  Aff --> Fast["pytest unit\n+ lean tox"]
  Night["Nightly schedule"] --> Crawl["crawl all leaves"]
  Crawl --> Full["full suites\n+ tox matrices"]
  Full --> Partials["per-leaf coverage.xml"]
  Partials --> Rollup["combine / upload\nmonorepo total"]
  Rollup --> Detect["anomaly detection"]
  Detect --> Owners["alert CODEOWNERS\nof failing leaves"]
  Detect --> Dash["dashboard / report\ncauses for debug"]
            

Reference stack: pytest + coverage.py [30] locally; Codecov / Coveralls / Sonar (or a simple HTML report published next to the docs portal) for the accumulated nightly view. Same rule as everything else: one poe coverage-nightly (or equivalent) that CI calls โ€” no snowflake nightly scripts per leaf.

๐Ÿšจ Alerting CODEOWNERS on nightly anomalies

When the nightly crawler finds something wrong, do not spam #engineering. Route to the CODEOWNERS of the failing leaf (and platform only for rollup / infra symptoms). Ground the policy in Rob Ewaschukโ€™s My Philosophy on Alerting [31] (widely cited in Google SRE practice): pages should be urgent, important, actionable, and real โ€” prefer symptoms over raw causes, and keep cause detail on dashboards / in the alert body for debugging.

Map that to Repo-Health nightlies:

  • ๐Ÿฉบ Alert on symptoms โ€” e.g. โ€œleaf libs/foo-bar-baz-qux nightly is red,โ€ โ€œmonorepo coverage dropped > N% WoW,โ€ โ€œtox py312 factor failed for 3 shared libs,โ€ โ€œintegration suite timed out for services/billing.โ€ These are user/platform pain signals for that pathโ€™s owners.
  • ๐Ÿ” Attach causes in the payload / dashboard โ€” failed test names, flake retries, Python version, runner arch, coverage ฮ”, last green SHA โ€” so owners can debug without a second page for every proximate cause.
  • ๐Ÿ‘ค Route by CODEOWNERS โ€” resolve /libs/foo-bar-baz-qux/ โ†’ @org/foo-bar-owners (Slack/Teams/PagerDuty/ GitHub Issues). Platform owns rollup symptoms (dockers/, CI templates, crawler itself).
  • ๐Ÿ”‡ Donโ€™t page on every cause โ€” a single flaky test failure is a ticket/dashboard item; a leaf that was green for 14 days and is now red is a page. Err toward removing noisy alerts.

Example anomaly classes the nightly should detect and fan out:

  • ๐Ÿ’ฅ Suite regression โ€” previously green leaf now failing unit / integration / tox env
  • ๐Ÿ“‰ Coverage cliff โ€” leaf or monorepo total drops beyond threshold
  • ๐Ÿ Matrix break โ€” lib fails on a Python/OS/arch still required by downstream apps/services
  • โฑ๏ธ Health of the crawler โ€” nightly itself didnโ€™t finish / couldnโ€™t discover leaves (symptom: โ€œRepo-Health blindโ€ โ†’ page platform)
  • ๐Ÿ” Flake storms โ€” same test fails intermittently above a rate (ticket the owners; page only if a release path is blocked)
# conceptual alert routing
for anomaly in nightly_anomalies:
    paths = anomaly.affected_paths          # e.g. libs/foo-bar-baz-qux/**
    owners = resolve_codeowners(paths)      # from CODEOWNERS
    notify(
        owners,
        symptom=anomaly.symptom,            # "nightly red" / "coverage cliff"
        causes=anomaly.debug_bundle,        # logs, SHA, matrix cell, โ€ฆ
        runbook=docs_url("repo-health"),
    )

Observability here is not just dashboards โ€” it is closed-loop ownership: measure the estate, detect symptoms, page the people who can fix that path, and keep causes visible without turning every log line into a pager event [31].

๐Ÿ”ฅ Blaze / Bazel and Buck โ€” why we did not start there

Two hyperscale lineages dominate this design space:

  • ๐ŸŸ  Google โ€” Blaze โ†’ Bazel [13] โ€” hermetic actions, fine-grained target graph, remote caching / remote execution, Starlark rules. Bazel is the open-source Blaze.
  • ๐Ÿ”ต Meta โ€” Buck โ†’ Buck2 [22] โ€” Metaโ€™s monorepo build system (Buck1 open-sourced earlier; Buck2 is the from-scratch Rust rewrite). Same class of problem: polyglot targets, hermeticity, remote execution (REAPI-compatible), rules in Starlark decoupled from the core [23].

For a hyperscale polyglot monorepo, Bazel or Buck2 is often the correct endgame. Both are the wrong first move for most orgs that just need shared libs + services in one Git repo.

โœ… Pros (Bazel / Buck2 class)

  • ๐Ÿงฎ Hermetic, reproducible builds โ€” inputs hash to outputs; โ€œworks on my machineโ€ shrinks dramatically.
  • โšก Incremental + remote cache โ€” unchanged targets are fetched, not rebuilt; CI and laptops can share a cache.
  • ๐Ÿ•ธ๏ธ Precise affected graph โ€” test/build only what the target graph says changed, across languages.
  • ๐ŸŒ Polyglot-native โ€” one system for Python, Go, Rust, Java/C++, protos, container images, etc.
  • ๐Ÿ” Buck2-specific upside โ€” dynamic dependencies (graph can grow mid-build from tool output), rules fully outside the Rust core, strong parallelism story vs Buck1 / vs phase-heavy designs.

โŒ Cons (same tax either way)

  • ๐Ÿง— Steep learning curve โ€” BUILD/BUCK files, Starlark rules, cells/workspaces, and rule ecosystems become a specialization.
  • ๐Ÿงฐ Toolchain takeover โ€” everyday language UX (uv, pytest, cargo test, IDE runners) often needs wrappers; onboarding tax is real.
  • ๐Ÿ‘ฅ Platform bottleneck โ€” one or two engineers become the only people who can land build changes.
  • ๐Ÿ’ธ Ops cost โ€” remote cache / RBE, rules upgrades, and language-rules churn are ongoing platform work, not a weekend migration.
  • ๐Ÿฅœ Overkill early โ€” for dozens of leaves, Blaze/Buck-class hermeticity is a sledgehammer.
  • ๐Ÿงช Ecosystem maturity tradeoffs โ€” Bazel has the broader open-source rules surface today; Buck2 is battle-tested at Meta but the public ecosystem / release cadence is younger โ€” picking either is a multi-year platform bet.

๐Ÿšซ Why we did not use Bazel or Buck first

We wanted a monorepo that engineers can extend on day two without learning a second build language. The uv workspace + poe tasks + forge-native child pipelines give us path deps, affected CI, and shared templates with tools people already know. Blaze/Bazel and Buck/Buck2 stay on the roadmap for when polyglot scale or CI minutes force hermetic remote execution โ€” not as the admission price to have libs/ and services/ in one Git repo.

Rule of thumb: earn Bazel or Buck2. Start with the graph + CI contracts in this post; graduate to hermetic monorepo builders when the complexity tax is clearly cheaper than the CI bill โ€” then choose based on your language mix, rules ecosystem, and whether you already have REAPI infrastructure.

๐Ÿณ Shared container assets โ€” dockers/

Centralize image plumbing so every leaf does not ship a private snowflake Dockerfile:

dockers/
โ”œโ”€โ”€ bases/
โ”‚   โ”œโ”€โ”€ python-runtime/Dockerfile    # org Python base
โ”‚   โ””โ”€โ”€ go-runtime/Dockerfile
โ”œโ”€โ”€ templates/
โ”‚   โ””โ”€โ”€ python-service/Dockerfile    # multi-stage template leaves COPY from
โ”œโ”€โ”€ compose/
โ”‚   โ”œโ”€โ”€ local-deps.yml               # postgres, redis, localstack, โ€ฆ
โ”‚   โ””โ”€โ”€ mesh-stub.yml
โ””โ”€โ”€ README.md

Leaves keep a thin Dockerfile (or build args) that FROM the org base / template. CD rebuilds dockers/bases/* on change, then rebuilds dependent apps/* / services/* images.

๐Ÿช Cookiecutters โ€” scaffold, donโ€™t teach the bolts

The monorepoโ€™s internal contracts (workspaces, CI stubs, naming maps, docs nodes, CODEOWNERS rows) are platform knowledge. Downstream users should not need to learn them. Keep golden-path generators under cookiecutters/ (name is historical โ€” the engine can be any of the tools below) and expose them only through task-runner entrypoints (poe new-*).

๐Ÿ› ๏ธ Scaffolding engines โ€” pick one org-wide

  • ๐Ÿช Cookiecutter [26] โ€” classic Jinja templates; fire-and-forget generation. Simple, ubiquitous, polyglot. Weak at updating already-scaffolded leaves when the template evolves.
  • ๐Ÿ“‹ Copier [27] โ€” Cookiecutterโ€™s smarter cousin: Jinja templates + answers file + template updates with 3-way merges. Strong default when you want a golden path that can evolve without rewriting every leaf by hand.
  • ๐Ÿงฌ Projen [28] โ€” project config as code (synthesize package.json, CI, lint, โ€ฆ from a typed .projenrc). Generated files are managed, not hand-edited โ€” best when you want โ€œcattle, not petsโ€ consistency and a central push of config upgrades (popular in TS/CDK worlds; works beyond JS via jsii).
  • ๐Ÿ“ฆ Other options in the same niche โ€” Yeoman, Crane, language CLIs (cargo new, npm create) wrapped by poe so the user surface stays poe new-* regardless of engine.

Recommendation: Copier for polyglot monorepos that need template upgrades; Cookiecutter if you only need create-once scaffolding; Projen when most leaves are TS/Node (or CDK) and you want synthesized, non-editable project config. Do not mix three engines without a very good reason โ€” the directory can still be called cookiecutters/ even if the binary is copier.

cookiecutters/
โ”œโ”€โ”€ python-lib/               # Copier/Cookiecutter template โ€” or
โ”œโ”€โ”€ python-service/           #   projen project type definitions
โ”œโ”€โ”€ python-project/
โ”œโ”€โ”€ js-app/
โ”œโ”€โ”€ go-service/
โ””โ”€โ”€ README.md                 # which poe task โ†’ which template/engine

# root pyproject.toml โ€” illustrative (swap cookiecutter โ†” copier as needed)
[tool.poe.tasks.new-python-lib]
help = "Scaffold a namespaced Python lib under libs/"
cmd = "copier copy cookiecutters/python-lib libs"

[tool.poe.tasks.new-python-service]
cmd = "copier copy cookiecutters/python-service services"

[tool.poe.tasks.new-js-app]
cmd = "copier copy cookiecutters/js-app apps"

# if using projen instead:
# [tool.poe.tasks.new-js-app]
# cmd = "projen new --from ./cookiecutters/js-app โ€ฆ"

Each template / project type should emit a complete leaf in one shot:

  • ๐Ÿ“ฆ correct directory + org-namespaced package layout
  • ๐Ÿงพ pyproject.toml / language manifest wired into the workspace
  • ๐Ÿงฉ CI child stub (.gitlab-ci.yml or GitHub stub + ci.yml)
  • ๐Ÿ“š starter docs/ node
  • ๐Ÿ‘ค CODEOWNERS snippet / team placeholder
  • ๐Ÿณ thin Dockerfile that uses FROM with dockers/ bases when relevant

UX goal: poe new-python-lib โ†’ answer three prompts โ†’ open a PR. No wiki spelunking required. Platform owns the templates; product teams consume the CLIs.

๐Ÿ›ก๏ธ CODEOWNERS, ACL, and merge gates

A monorepo without path-level ownership is a shared writable disk. Every downstream leaf needs an explicit owner set, and the forge must refuse to ship without their approval.

# .github/CODEOWNERS  (or .gitlab/CODEOWNERS)
# Default โ€” platform team
*                                @org/platform

# Leaf ownership โ€” required reviewers for that path
/libs/foo-bar-baz-qux/           @org/ml-platform @org/foo-bar-owners
/services/billing/               @org/billing
/apps/console/                   @org/console
/dockers/                        @org/platform
/cookiecutters/                  @org/platform
/iac/                            @org/platform @org/sre
/docs/                           @org/platform
  • ๐Ÿ”’ Branch protection / MR approval rules โ€” require CODEOWNERS review on the default branch; dismiss stale approvals on new pushes; block merge if checks fail.
  • ๐Ÿ‘ฅ Leaf teams own leaves โ€” product groups are listed on their paths; platform owns dockers/, cookiecutters/, CI templates, and shared libs/* that many consumers depend on (or a dedicated libs review group).
  • ๐Ÿšซ No self-merge of critical paths โ€” especially iac/, deploy templates, and base images.
  • ๐Ÿชช ACL beyond Git โ€” registry push, cloud deploy roles, and secrets access mapped to the same owner teams (OIDC / environment protection rules on GitHub; protected environments on GitLab). CODEOWNERS stops bad merges; cloud ACL stops bad deploys.
  • ๐Ÿ“œ Document the contract in docs/ / CONTRIBUTING.md โ€” who owns what, how to request ownership changes, and that unapproved path changes do not ship.

๐Ÿค– How AI tools help maintain the repo

Treat AI the same way you treat CI: encoded policy, not vibes. The monorepo should teach agents (and humans) the contracts so scaffolds, refactors, docs, and reviews stay on the golden path. Below is a practical operating model.

๐Ÿค– AI in the monorepo lifecycle
flowchart LR
  Rules[".cursor/rules\nCLAUDE.md\ndocs/ai/*"]
  Author["Authoring agents\nCursor / Claude / โ€ฆ"]
  MCP["MCP servers\nforge ยท docs ยท registry"]
  PR["PR / MR opened"]
  Review["Review agent\npolicy check"]
  Humans["CODEOWNERS\nhuman approve"]
  Merge["Merge + CD"]

  Rules --> Author
  MCP --> Author
  Author --> PR
  PR --> Review
  Rules --> Review
  MCP --> Review
  Review --> Humans
  Humans --> Merge
            

๐Ÿ“ 1. Encode the contracts where agents look first

  • ๐Ÿ“ .cursor/rules/ โ€” short Cursor rules for topology, naming (foo-bar โ†’ foo/bar), import DAG bans, โ€œuse poe new-* โ€” donโ€™t hand-roll leaves,โ€ docs-node requirements, and PR style.
  • ๐Ÿ“ CLAUDE.md / Claude project rules โ€” same invariants for Claude Code / Claude in the IDE so you are not maintaining two contradictory policy worlds.
  • ๐Ÿ“– docs/ + CONTRIBUTING.md + ADRs โ€” source of truth; rules should link here, not duplicate novels.
  • ๐Ÿงช docs/ai/ โ€” versioned prompts and checklists (pr-review.md, scaffold-leaf.md) that both humans and bots run.

๐Ÿ› ๏ธ 2. Day-to-day maintainer jobs AI is good at

  • ๐Ÿช Scaffold leaves โ€” โ€œadd libs/acme-billing-clientโ€ โ†’ agent runs poe new-python-lib (Copier/Cookiecutter/Projen), fills prompts, opens a branch. No free-form file inventing.
  • ๐Ÿ“š Keep docs honest โ€” when a public API changes, agent updates the leaf docs/ node and flags portal nav gaps before merge.
  • ๐Ÿ” Propagate template upgrades โ€” after cookiecutters/ or CI templates change, agent opens MRs that re-sync leaves (especially strong with Copier update / Projen synth).
  • ๐Ÿงน Repo hygiene โ€” find import-DAG violations, missing CODEOWNERS rows, orphaned Dockerfiles, stale path filters, docs-only leaves without poe docs coverage.
  • ๐Ÿงพ Changelog / migration notes โ€” draft ADR stubs and contributor-facing migration steps when a shared lib breaks consumers.
  • ๐Ÿ› CI archaeology โ€” read failing job logs via MCP, propose the minimal fix, re-run the leaf child pipeline.

๐Ÿ”Œ 3. MCP โ€” give agents tools, not pastebins

  • ๐Ÿงฐ Wire MCP servers for the forge (GitHub/GitLab), issue tracker, docs search, and package registry metadata so agents can open MRs, inspect checks, and query ownership without brittle shell one-offs.
  • ๐Ÿ” Scope credentials: read-heavy for review bots; write only for a bot identity that obeys the same ACL as humans.
  • ๐Ÿงญ Prefer MCP + in-repo rules over stuffing the entire monorepo into a single prompt context window.

๐Ÿ•ต๏ธ 4. Review agents on every PR / MR

  • ๐Ÿค– On pull_request / merge_request open/sync, run a review agent (Actions / GitLab job, or hosted bots such as Copilot / CodeRabbit-class reviewers) against docs/ai/pr-review.md.
  • Checklist the agent should enforce:
    • import DAG + no leafโ†’leaf Python imports
    • org namespace naming on new libs
    • CI stub + docs/ node present for new leaves
    • no secrets; Dockerfiles FROM org bases
    • CODEOWNERS path touched has owners listed
  • โœ… Make the result a required check (pass / fail) or at least a blocking โ€œchanges requestedโ€ comment style โ€” not a silent Slack side-channel.
  • ๐Ÿ‘ค Agents never bypass CODEOWNERS โ€” humans still approve; the bot only fails the check or leaves review comments.

โš ๏ธ 5. Guardrails โ€” what AI must not do

  • ๐Ÿšซ Invent a new top-level directory or skip poe new-* for โ€œspeed.โ€
  • ๐Ÿšซ Self-approve or merge using admin tokens.
  • ๐Ÿšซ Edit iac/, deploy templates, or dockers/bases without the owning team in the loop.
  • ๐Ÿšซ Treat generated Projen/Copier-managed files as free-edit surfaces when the engine owns them.

Bottom line: AI maintains the monorepo by executing and enforcing written contracts โ€” Cursor/Claude rules for authors, MCP for tool access, PR/MR agents for review โ€” while ACL + CODEOWNERS remain the hard gate that prevents unapproved changes from shipping.

โ˜๏ธ IaC next to the graph

Keep Terraform (or Pulumi) under iac/ with the usual module vs. stack split:

iac/
โ”œโ”€โ”€ modules/          # reusable primitives (network, k8s, bucket, db)
โ”œโ”€โ”€ stacks/
โ”‚   โ”œโ”€โ”€ platform/     # shared cluster / mesh / observability
โ”‚   โ””โ”€โ”€ services/     # per-service wiring (IAM, DNS, secrets refs)
โ””โ”€โ”€ README.md

Hard rule: ๐Ÿ” no secrets in Git โ€” remote state + vault / cloud secret manager only. Service deploy pipelines consume outputs; they do not embed credentials.

Reference: Terraform docs [9].

๐Ÿ“š Docs portal โ€” landing page + aggregate from leaves

Top-level docs/ is not a junk drawer of markdown. It is the documentation portal: the landing page, global nav, org ADRs, onboarding, and the glue that mounts every downstream leafโ€™s docs into one published site.

docs/                              # portal root (landing + chrome)
โ”œโ”€โ”€ index.md                       # landing page
โ”œโ”€โ”€ getting-started.md
โ”œโ”€โ”€ adr/                           # architecture decision records
โ”œโ”€โ”€ architecture/                  # C4 / Mermaid / D2
โ”œโ”€โ”€ mkdocs.yml                     # or conf.py โ€” portal config
โ””โ”€โ”€ overrides/                     # theme chrome

libs/foo-bar-baz-qux/docs/         # downstream docs node
โ”œโ”€โ”€ index.md
โ””โ”€โ”€ api/                           # or rely on autodoc / mkdocstrings

services/billing/docs/
โ”œโ”€โ”€ index.md
โ”œโ”€โ”€ runbooks/
โ””โ”€โ”€ diagrams/

projects/claims-etl/docs/
โ””โ”€โ”€ index.md

๐Ÿšข CD builds docs on the fly and publishes

Do not ask humans to copy leaf markdown into docs/. A docs CD child node (same parent/child pattern as CI) should:

  1. ๐Ÿ” Discover docs nodes under apps/*/docs, libs/*/docs, projects/*/docs, services/*/docs.
  2. ๐Ÿงฉ Generate / assemble the portal nav (mount each leaf under e.g. /libs/foo-bar-baz-qux/, /services/billing/).
  3. โš™๏ธ Build API reference from docstrings where configured (autodoc / mkdocstrings).
  4. ๐Ÿ“ฆ Emit a static site artifact.
  5. ๐Ÿš€ Publish on merge to the default branch (GitHub Pages, GitLab Pages, S3+CloudFront, or Read the Docs).

Path filters: a leaf-only docs change rebuilds that leafโ€™s section (or a cheap full static rebuild โ€” usually fine). A portal chrome change under top-level docs/ rebuilds the whole site. Wire this as poe docs locally and the same task in the docs CD child.

๐Ÿ“š Portal aggregates downstream docs nodes
flowchart LR
  subgraph leaves["Downstream docs nodes"]
    L1["libs/*/docs"]
    L2["services/*/docs"]
    L3["apps/*/docs"]
    L4["projects/*/docs"]
  end
  Portal["docs/\nlanding + nav + ADRs"]
  CD["Docs CD child\npoe docs โ†’ build"]
  Site["Published site\nPages / S3 / RTD"]

  L1 --> CD
  L2 --> CD
  L3 --> CD
  L4 --> CD
  Portal --> CD
  CD --> Site
            

๐Ÿ Python docs tooling โ€” options

Pick one stack org-wide. Mixing Sphinx in half the leaves and MkDocs in the other half is how portals die.

  • ๐Ÿ“˜ MkDocs + Material for MkDocs + mkdocstrings [14] [15] [16] โ€” markdown-first portal, excellent UX, easy multi-section nav. mkdocstrings pulls Python API docs from docstrings. Best default for a monorepo landing page that aggregates many leaves.
  • ๐Ÿ“— Sphinx + autodoc + MyST + Furo [17] [18] [24] โ€” deepest Python API / cross-ref story; steeper config. Prefer when you need rich intersphinx, complex API trees, or already live in Sphinx. Live example: docs.slickml.com [25] (Sphinx + Furo).
  • ๐Ÿ“„ pdoc [19] โ€” low-ceremony API sites from docstrings. Great per-lib artifact; weaker as the org-wide portal unless you wrap it.
  • ๐Ÿ““ Jupyter Book [20] โ€” best when projects/* are notebook-heavy; usually a section inside the portal, not the whole portal.
  • โ˜๏ธ Hosting โ€” GitHub Pages / GitLab Pages for forge-native CD; Read the Docs [21] if you want versioned docs / PR previews without running your own Pages bucket.

Recommendation: MkDocs Material at docs/ as the portal, mkdocstrings pointed at each libs/* package path, leaf narrative docs living under each leafโ€™s docs/, assembled by poe docs in CD. Use Sphinx only if API cross-refs become the product. Keep Jupyter Book as an opt-in section for research-shaped projects/*.

๐ŸŽจ Diagrams as code (inside the portal)

Architecture that only exists in slide decks drifts. Prefer text-native diagram tools in portal + leaf docs:

  • ๐Ÿงœโ€โ™‚๏ธ Mermaid [10] โ€” flowcharts, C4-ish graphs, sequences; renders in GitHub/GitLab markdown and MkDocs plugins.
  • โœ๏ธ D2 [11] โ€” declarative layouts with stronger aesthetic defaults for system diagrams.
  • ๐Ÿ›๏ธ Structurizr / C4 [12] โ€” when you need formal C4 model โ†’ views.

Minimum bar: every new services/* leaf ships a Mermaid (or D2) context diagram in its docs/ before the first deploy template lands.

๐Ÿ—บ๏ธ Rollout sequence

  1. ๐Ÿงพ Freeze the directory contracts + import DAG in an ADR.
  2. ๐Ÿงฑ Stand up root uv workspace + shared ruff/mypy/poe/tox config.
  3. ๐Ÿช Land cookiecutters/ + poe new-* tasks so new leaves are never hand-rolled.
  4. ๐Ÿ‘ค Turn on CODEOWNERS + branch protection / MR approval rules before the repo has many writers.
  5. ๐Ÿ“ฆ Extract 2โ€“3 already-shared modules into libs/ using hyphenated org namespaces (acme-platform-logging โ†’ acme/platform/logging).
  6. ๐Ÿ“š Stand up the docs/ portal landing page + poe docs CD publish; require a docs/ node on each new leaf.
  7. ๐Ÿค– Add .cursor/rules / Claude rules + a PR/MR review agent check wired to CONTRIBUTING.md.
  8. ๐Ÿ“ Require pytest on every leaf; tox matrices on shared libs; schedule a nightly coverage crawl for the whole monorepo.
  9. ๐Ÿ›ฐ๏ธ Migrate one microservice into services/ with path deps + a template pipeline.
  10. ๐Ÿงฌ Add one domain projects/ leaf that consumes the same libs.
  11. โ˜๏ธ Land baseline iac/modules + one stack wired to that service.
  12. ๐Ÿ“ˆ Only then mass-migrate โ€” with ownership, scaffolds, and affected-test CI already green.

๐Ÿช™ My 2 cents

The monorepo pays rent only if the graph is real. Folder names alone are cosplay.

Make these contracts non-optional:

  • ๐Ÿ”— Path dependencies + an enforceable import DAG
  • ๐Ÿงฉ Leaf CI child nodes under shared parent templates
  • ๐Ÿท๏ธ Org-namespaced libs (foo-bar โ†’ foo/bar)
  • ๐Ÿช poe new-* scaffolds (Copier / Cookiecutter / Projen) so teams never hand-roll leaves
  • ๐Ÿ“š First-class docs/ portal aggregated from every leaf
  • ๐Ÿ›ก๏ธ CODEOWNERS + ACL โ€” unapproved path changes do not ship
  • ๐Ÿณ Shared dockers/ bases, not snowflake Dockerfiles
  • ๐Ÿ’“ Repo-Health โ€” pytest, tox matrices, nightly coverage crawl, symptom-based alerts to CODEOWNERS

Tooling posture:

  • โšก Start with uv + poe + forge-native CI
  • ๐Ÿ”ฅ Earn Blaze/Bazel or Buck/Buck2 later โ€” donโ€™t pay that tax on day one
  • ๐Ÿค– Encode the same contracts for AI (Cursor/Claude rules, MCP, PR/MR review agents)

๐ŸŒฑ Treat the repository itself as something you design โ€” not something that accumulates.

๐Ÿ“š References

  1. Dan Hipschman, โ€œOur Python Monorepo,โ€ Opendoor / Open House โ€” inspiration for this design, medium.com/opendoor-labs/our-python-monorepo-d34028f2b6fa
  2. Astral, uv documentation, docs.astral.sh/uv
  3. Astral, Ruff documentation, docs.astral.sh/ruff
  4. mypy, mypy โ€” static typing for Python, mypy-lang.org
  5. Microsoft, Pyright, github.com/microsoft/pyright
  6. Nat Knight et al., Poe the Poet, poethepoet.natn.io
  7. tox, tox documentation, tox.wiki
  8. tox-dev, tox-uv, github.com/tox-dev/tox-uv
  9. HashiCorp, Terraform documentation, developer.hashicorp.com/terraform/docs
  10. Mermaid, documentation, mermaid.js.org
  11. Terrastruct, D2, d2lang.com
  12. Structurizr, C4 model tooling, structurizr.com
  13. Bazel (open-source Blaze), bazel.build
  14. MkDocs, www.mkdocs.org
  15. Material for MkDocs, squidfunk.github.io/mkdocs-material
  16. mkdocstrings, mkdocstrings.github.io
  17. Sphinx, sphinx-doc.org
  18. MyST Parser, myst-parser.readthedocs.io
  19. pdoc, pdoc.dev
  20. Jupyter Book, jupyterbook.org
  21. Read the Docs, readthedocs.org
  22. Buck2 (Meta), buck2.build
  23. Meta Engineering, โ€œBuild faster with Buck2: Our open source build system,โ€ engineering.fb.com/โ€ฆ/buck2-open-source-large-scale-build-system
  24. Furo (Sphinx theme), pradyunsg.me/furo
  25. SlickML documentation (Sphinx + Furo example), docs.slickml.com
  26. Cookiecutter, github.com/cookiecutter/cookiecutter
  27. Copier, github.com/copier-org/copier / copier.readthedocs.io
  28. Projen, github.com/projen/projen / projen.io
  29. pytest, docs.pytest.org
  30. Coverage.py, coverage.readthedocs.io
  31. Rob Ewaschuk, โ€œMy Philosophy on Alerting,โ€ docs.google.com/document/d/199PqyG3UsyXlwieHaqbGiWVa8eMWi8zzAn0YfcApr8Q