Skip to content

Generate modular C# package families from OpenAPI tags #393

Description

@HavenDV

Motivation

Large generated SDKs such as tryAGI.GitHub contain thousands of generated source files even when a consumer needs only a small API area. This increases restore/package validation time, IDE load, compiler memory, and build time for both the SDK repository and downstream consumers.

AutoSDK already understands OpenAPI tags and supports tag filtering. It should be able to turn that information into a modular package graph instead of requiring every generated repository to invent its own project splitter.

Proposed feature

Add an opt-in generation mode (for example, autosdk generate --split-by-tags --package-id tryAGI.GitHub) that emits a family of projects/packages:

tryAGI.GitHub.Core       shared models, serialization, auth, options, and runtime support
tryAGI.GitHub.Actions    clients and operations tagged `actions`
tryAGI.GitHub.Issues     clients and operations tagged `issues`
tryAGI.GitHub.Repos      clients and operations tagged `repos`
...
tryAGI.GitHub            dependency-only metapackage preserving the full-install experience

Consumers can reference only the tag packages they use; existing consumers can keep referencing the metapackage.

Important architectural constraints

This cannot be implemented by assigning the current generated files to arbitrary .csproj files:

  • C# partial types cannot span assemblies.
  • Shared public models/runtime types must be emitted once in Core, not duplicated in every tag package.
  • Tag assemblies must reference Core without introducing Core -> tag cycles.
  • Generated clients currently share request options, polling helpers, server selection, auth/OAuth coordination, JSON source-generation contexts, converters, and response helpers. Their visibility and ownership need an explicit cross-assembly design.
  • The current root client exposes tag clients as properties. Modular mode needs either a generated facade in a separate aggregate assembly, extension/factory APIs, or direct tag-client construction; it must not depend on cross-assembly partial classes.
  • Operations without tags need a deterministic package (for example, Untagged or Default).
  • Multiple tags on one operation, sanitized tag-name collisions, case-only collisions, reserved package names, and filesystem-invalid characters must be handled deterministically.
  • Model ownership must account for transitive schema dependencies across tags. A safe first version may place all models in Core; future optimization can split models only when dependency analysis proves it safe.

Suggested output

GeneratedPackages/
  tryAGI.GitHub.Core/
    tryAGI.GitHub.Core.csproj
    Generated/
  tryAGI.GitHub.Actions/
    tryAGI.GitHub.Actions.csproj
    Generated/
  tryAGI.GitHub.Issues/
    tryAGI.GitHub.Issues.csproj
    Generated/
  tryAGI.GitHub/
    tryAGI.GitHub.csproj
  tryAGI.GitHub.slnx
  autosdk-packages.json

autosdk-packages.json should provide a stable machine-readable tag-to-package mapping so generated repositories can build, test, document, and publish the family without rediscovering names.

Package behavior

  • Every tag package references Core.
  • The base package is a metapackage referencing Core and every generated tag package.
  • Package metadata and versions stay aligned across the family.
  • Package references should be used for published output while project references are available for repository builds.
  • Deterministic output and stale-project cleanup must work when tags are added, removed, or renamed.
  • Existing single-project generation remains the default; this is opt-in and backwards compatible.
  • Consider a configurable grouping/override file so very small or closely related tags can share one package and unstable upstream tag names do not force package churn.

Acceptance criteria

  • AutoSDK exposes a documented opt-in split-by-tags mode for generated C# SDK repositories.
  • A two-tag fixture generates Core, two independently consumable tag packages, a metapackage, a solution, and a deterministic manifest.
  • Each tag package builds and packs independently with only Core as its generated dependency.
  • A consumer referencing one tag package can construct its client and call its methods without referencing the metapackage or unrelated tag assemblies.
  • A consumer referencing the metapackage retains an ergonomic full-SDK experience.
  • Shared types have one assembly identity and no duplicate-type ambiguity when multiple tag packages are referenced.
  • Auth, OAuth, server selection, request options, polling, streaming responses, pageable helpers, and System.Text.Json source generation have cross-assembly tests.
  • Tag/package naming and multi-tag/untagged operations have deterministic tests.
  • Regeneration removes only stale AutoSDK-owned projects/files and preserves user-owned repository files.
  • A tryAGI.GitHub canary reports before/after source count, package size, restore time, build time, compiler peak memory, and NuGet validation time for both a focused tag package and the metapackage.

Initial rollout

Use tryAGI.GitHub as the first large canary after the generic fixture passes. Keep the existing package as the aggregate metapackage, publish modular packages in the same version family, then migrate Advantage to only the GitHub tag packages it actually uses.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions