Skip to content

API discovery: reactor.api.txt only covers 5 categories, agents can't find the rest of the surface #416

@codemonkeychris

Description

@codemonkeychris

Summary

skills/reactor.api.txt is the canonical index agents use to discover the Reactor API surface, but it only catalogs five sections:

  • Factories (Microsoft.UI.Reactor.Factories.*)
  • Modifiers (extension methods on Element)
  • Hooks (RenderContext / Component)
  • Theme tokens
  • Enums

This leaves big swaths of public API undiscoverable from the index file, including (non-exhaustive):

  • Properties / init-only fields on public records — e.g. WindowSpec.Opacity, WindowSpec.NoActivate, WindowSpec.IgnorePointerInput, plus all the existing fields like WindowSpec.Title, MinWidth, Backdrop, etc.
  • Instance methods on public classes — e.g. ReactorWindow.SetOpacity, SetPosition, SetSize, SetNoActivate, SetIgnorePointerInput, Update, Mount, Activate, Hide, Show, Close, CenterOnScreen, …
  • Public types themselves (records, sealed classes, structs) that aren't reachable via a Factories/Hooks/Modifiers method — e.g. DockManager, DockTabGroup, DockSplit, WindowSpec, BackdropChoice, WindowKey, Command, …
  • Constructors and overloads of public types
  • Events on public classes — e.g. ReactorWindow.Closing, Activated, Closed, DpiChanged

Motivating example

While working on PR #415 (feat/window-layered-attrs), I added three new init-only properties to WindowSpec and three matching instance methods on ReactorWindow. After committing, ran mur --regen-api — both copies of reactor.api.txt came back unchanged, because none of the new surface fits the five sections the index catalogs.

That's not a bug in the regen tool — it's a gap in what the index covers. The end result is that an agent picking up this codebase cold has no way to discover (a) the new APIs we just added, or (b) most of the existing window/docking/command surface, from the index alone.

Why it matters for agents

The Reactor docs deliberately push agents toward reactor.api.txt as the source of truth ("Source of truth: Reactor.dll public surface" — header of the file). The hope is that agents have a single curated catalog to look at instead of grepping the codebase. Today that promise is half-kept: factory-style fluent code is well-covered; everything else requires the agent to fall back to grep / Glob / opening Element.cs / etc.

This makes agent-driven work less reliable in three concrete ways:

  1. Missed APIs. An agent that doesn't realize ReactorWindow.SetPosition exists may reach for a Win32 P/Invoke or a less-good workaround.
  2. Wrong abstractions. An agent that doesn't see a record's properties may invent a new helper instead of using the existing init-only field.
  3. Stale references. Agents trained on older versions can't easily verify whether Foo.Bar still exists.

Possible directions (not prescriptive)

A few options, in increasing order of effort:

  1. Document the gap. Update the reactor.api.txt header to be explicit about what's covered and what isn't, and point to the right fallback (e.g. "for public records / methods on classes, see src/Reactor/**/*.cs directly"). Cheapest fix, doesn't actually solve the discovery problem but stops false promises.

  2. Add a sixth section: "Public types". Have Reactor.SignaturesGen emit a per-type catalog of constructors / properties / methods / events for every public, non-static, non-Factories type in Reactor.dll. Same toolchain, larger file. Risk: file size grows non-trivially.

  3. Generate a structured API surface file (e.g. reactor.api.json or per-namespace markdown) that an agent can pull selectively. Roslyn's public API tracking convention (PublicAPI.Shipped.txt / PublicAPI.Unshipped.txt) is one well-trodden pattern; it also gives us PR-time review of breaking changes for free.

  4. Augment with a /discover skill that lets an agent ask "what's the API for ReactorWindow?" and resolve against a generated catalog on demand. Higher-overhead but matches how agents tend to work.

Option 2 is the smallest change that meaningfully closes the gap. Option 3 has more long-term value but is a bigger lift.

Acceptance criteria

  • An agent reading the canonical API index (whatever form it takes) can discover:
    • Public properties / init-only fields on every public type
    • Public instance methods on every public type
    • Public events on every public type
    • Constructors / overloads
  • The regen pipeline catches new surface added in a PR (the WindowSpec.Opacity example would have produced a diff on mur --regen-api)
  • The file format remains diffable and reviewable in a PR (i.e. not just a binary symbol dump)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions