Architecture
Codebase layout, module dependencies, and design decisions.
Directory layout
wyattowalsh/
├── scripts/
│ ├── cli/ # Typer CLI package
│ │ ├── _app.py # Root app, --version, sub-app registration
│ │ ├── generate.py # Generate subcommands (banner, qr, word-cloud, …)
│ │ ├── config_cmd.py # Config subcommands (view, save, generate-default)
│ │ ├── settings_cmd.py # show-settings command
│ │ └── dev.py # Dev tools (format, lint, test, clean, docs)
│ ├── config.py # Pydantic config models + load/save
│ ├── utils.py # Logger (Loguru), Rich console
│ ├── banner.py # SVG banner (~1730 lines)
│ ├── banner_patterns.py # PatternType enum (zero-dep)
│ ├── qr.py # QR code generator
│ ├── word_clouds.py # Word cloud orchestrator
│ ├── word_cloud_renderers.py # Pure-SVG rendering backends
│ ├── techs.py # Technology parser
│ ├── readme_sections.py # README assembler (~1548 lines)
│ ├── readme_svg.py # SVG rendering helpers for README cards
│ ├── skills.py # Skills badge generator
│ ├── generative.py # Generative art entry
│ ├── animated_art.py # Animated art CLI compatibility shim over scripts/art/*
│ ├── fetch_metrics.py # GitHub metrics fetcher
│ ├── fetch_history.py # GitHub history fetcher
│ ├── _github_http.py # Shared GitHub HTTP helpers
│ └── art/
│ ├── shared.py # seed_hash, _hex_slice, Noise2D
│ ├── _dev_profiles.py # Mock profiles for local testing
│ ├── ink_garden.py # Ink garden SVG (~2027 lines)
│ ├── topography.py # Topographic contour art (~1170 lines)
│ └── animate.py # Animation primitives
├── tests/
│ └── fixtures/
│ └── ink_garden/ # Golden SVG files
├── .github/
│ ├── assets/
│ │ ├── img/ # Generated SVGs/PNGs
│ │ ├── topics.md # Starred-repo topics (auto-updated)
│ │ └── languages.md # Starred-repo languages (auto-updated)
│ └── workflows/
│ └── profile-updater.yml # Main CI workflow
├── docs/ # This Fumadocs site
├── config.yaml # ProjectConfig (edit this)
└── skills.yaml # Skills badge definitionsModule dependency graph
cli/
├── _app.py
│ ├── generate.py (generate sub-app)
│ ├── config_cmd.py (config sub-app)
│ ├── dev.py (dev sub-app)
│ └── settings_cmd.py (show-settings)
└── generate.py
├── banner.py (lazy — imported inside command body)
├── qr.py (lazy)
├── word_clouds.py (lazy)
├── techs.py (lazy)
├── readme_sections.py (lazy)
├── skills.py (lazy)
├── generative.py (lazy)
└── animated_art.py (lazy compatibility shim over scripts/art/*)
banner.py
├── banner_patterns.py (PatternType)
├── svgwrite
└── numpy
ink_garden.py / topography.py
├── art/shared.py (seed_hash, Noise2D)
└── numpy
fetch_metrics.py + fetch_history.py
└── _github_http.py (_headers, _graphql)Lazy imports
All heavy domain modules (banner, qr, word_clouds, art) are lazily imported inside CLI command function bodies in cli/generate.py. This keeps import scripts.cli fast even when optional extras aren't installed.
Configuration flow
config.yaml → load_config() → ProjectConfig (Pydantic v2)
│
┌─────────┼─────────┐
BannerSettings QRSettings WordCloudSettings ...
│
generate_banner(BannerConfig(**banner_settings))ProjectConfig uses mode="json" serialization to produce safe-loadable YAML (avoids Python-object YAML tags from Pydantic's HttpUrl type).
Logging
All modules use get_logger(module=__name__) from scripts/utils.py — a Loguru logger with structured JSON sinks in logs/json/ and plain text in logs/text/. Both directories are gitignored. Loguru calls use keyword arguments instead of f-strings: logger.info("msg: {key}", key=value).
utils.py calls loguru_logger.remove() at module import time. Importing any scripts.* module resets all Loguru handlers. Do not add file I/O, network calls, or subprocess calls to utils.py — it is imported by every other module.
Large modules
The five largest modules are intentionally monolithic — empirical co-change analysis shows they always change together with their art siblings, not in isolation (Parnas's "change together, stay together"):
| Module | Lines | Rationale |
|---|---|---|
art/ink_garden.py | ~2027 | Garden growth simulation |
banner.py | ~1730 | Single rendering pipeline |
readme_sections.py | ~1548 | One coherent assembler |
readme_svg.py | ~1330 | SVG card rendering helpers |
word_cloud_renderers.py | ~1230 | Tightly coupled rendering variants |
art/topography.py | ~1170 | Topographic contour map art |