From ea9cace98f8c3bafd1390e44fcc91e3d83c0f155 Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 13:19:57 -0400 Subject: [PATCH 1/6] add plan to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0f9d502..698fdf3 100644 --- a/.gitignore +++ b/.gitignore @@ -907,6 +907,7 @@ Autoredi.snk # AI AGENTS.md +codex-plan.md CLAUDE.md GEMINI.md SCRATCH.md From 2925818b65e9e48888c7f98d8cff15e9e7f7c40e Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 13:20:26 -0400 Subject: [PATCH 2/6] add vs code config --- .vscode/launch.json | 22 ++++++++++++++++++++++ .vscode/tasks.json | 21 +++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8374e96 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Benchmarks (Release)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "Build Benchmarks (Release)", + "program": "dotnet", + "args": [ + "run", + "--project", + "${workspaceFolder}/benchmarks/Autoredi.Benchmarks/Autoredi.Benchmarks.csproj", + "-c", + "Release" + ], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", + "stopAtEntry": false + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f6b6977 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build Benchmarks (Release)", + "type": "process", + "command": "dotnet", + "args": [ + "build", + "benchmarks/Autoredi.Benchmarks/Autoredi.Benchmarks.csproj", + "-c", + "Release" + ], + "problemMatcher": "$msCompile", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} From 3357781c92077c8babca8a2e71291ec3b2f02868 Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 13:22:19 -0400 Subject: [PATCH 3/6] updated to use the latest flogen --- src/Autoredi.Generators/Autoredi.Generators.csproj | 2 +- src/Autoredi.Generators/AutorediGenerator.cs | 2 +- .../Extraction/ServiceRegistrationExtractor.cs | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Autoredi.Generators/Autoredi.Generators.csproj b/src/Autoredi.Generators/Autoredi.Generators.csproj index 99670b6..e5cb413 100644 --- a/src/Autoredi.Generators/Autoredi.Generators.csproj +++ b/src/Autoredi.Generators/Autoredi.Generators.csproj @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Autoredi.Generators/AutorediGenerator.cs b/src/Autoredi.Generators/AutorediGenerator.cs index c8fa0d3..a7fa825 100644 --- a/src/Autoredi.Generators/AutorediGenerator.cs +++ b/src/Autoredi.Generators/AutorediGenerator.cs @@ -8,7 +8,7 @@ public sealed class AutorediGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { - Flow.Create(context) + context.Flow() .ForAttributeWithMetadataName(Names.AutorediAttFullName) .Select(ServiceRegistrationExtractor.Extract) .Collect() diff --git a/src/Autoredi.Generators/Extraction/ServiceRegistrationExtractor.cs b/src/Autoredi.Generators/Extraction/ServiceRegistrationExtractor.cs index b1ffdfe..be65d51 100644 --- a/src/Autoredi.Generators/Extraction/ServiceRegistrationExtractor.cs +++ b/src/Autoredi.Generators/Extraction/ServiceRegistrationExtractor.cs @@ -5,11 +5,15 @@ namespace Autoredi.Generators.Extraction; /// internal static class ServiceRegistrationExtractor { - public static ServiceRegistration Extract(GeneratorAttributeSyntaxContext context, CancellationToken ct) + public static ServiceRegistration Extract(AttributeContext context, CancellationToken ct) { - var symbol = (INamedTypeSymbol)context.TargetSymbol; - var attribute = context.Attributes.FirstOrDefault(); + ct.ThrowIfCancellationRequested(); + if (context.TargetSymbol is not INamedTypeSymbol symbol) + { + return null!; + } + var attribute = context.Attribute; if (attribute == null) { return null!; From f85e6531248985ea1151fd2984f9d4f4d2ab8bc2 Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 13:35:33 -0400 Subject: [PATCH 4/6] chore: update flowgen integration and tooling --- codex-plan.md | 15 + plans/autoredi-flowgen-rearchitecture.md | 547 +++++++++++++++++++++++ 2 files changed, 562 insertions(+) create mode 100644 codex-plan.md create mode 100644 plans/autoredi-flowgen-rearchitecture.md diff --git a/codex-plan.md b/codex-plan.md new file mode 100644 index 0000000..a7ff654 --- /dev/null +++ b/codex-plan.md @@ -0,0 +1,15 @@ +# Codex Collaboration Plan + +## Context +- Track actions I (the assistant) take so the human partner can see what needs to happen next. +- Focus areas so far: understand Autoredi's generator + Flowgen upgrade path, and note where the Flowgen skill instructions live. + +## Flowgen skill notes +- AGENTS instructions now have a symlink at `/Users/omoi/Developer/@repo/_dev/Autoredi/docs/AGENTS-link.md` so I can re-open the instructions easily. +- The Flowgen skill referenced there is located at `/usr/local/repo/flowgen-source-generator/SKILL.md` (plus the global `~/.codex/skills/flowgen-source-generators/SKILL.md`). It highlights Flowgen v0.7+ features such as `context.Flow()`/`Flow.Create(context)` starting points, `AttributeContext` in `.Select(...)`, and the existing `.Collect()`/`.EmitAll()` pipeline for N-to-1 outputs. + +## Work items +1. [ ] Upgrade `Autoredi.Generators` to Flowgen 0.7.0, switch the pipeline to `context.Flow()` and the new `AttributeContext` extractors, and keep the aggregated registration builder intact (this change is currently in progress). +2. [ ] Wait for the next set of instructions from the user once this groundwork is ready; the plan file will keep evolving as more tasks land here. + +*This file is git-ignored because it is meant for live collaboration notes only.* diff --git a/plans/autoredi-flowgen-rearchitecture.md b/plans/autoredi-flowgen-rearchitecture.md new file mode 100644 index 0000000..4f022c3 --- /dev/null +++ b/plans/autoredi-flowgen-rearchitecture.md @@ -0,0 +1,547 @@ +# Autoredi Rearchitecture Plan: Integration with Flowgen + +## Executive Summary + +This document outlines the plan to rearchitect Autoredi to use Flowgen as its underlying source generation framework. The primary challenge is bridging Flowgen's 1-to-1 pipeline model with Autoredi's requirement for N-to-1 aggregation (collecting multiple service registrations into a single extension method). + +## Current State Analysis + +### Autoredi's Current Architecture + +```mermaid +flowchart TD + A[SyntaxProvider: Find classes with AutorediAttribute] --> B[Collect all classes] + B --> C[Execute: Process all registrations] + C --> D[Validate registrations] + D --> E[Group by Group name] + E --> F[Generate single extension method with all groups] + F --> G[AddSource: AutorediExtensions.g.cs] +``` + +**Key Characteristics:** +- Uses `CreateSyntaxProvider` to find candidate classes +- Uses `.Collect()` to aggregate all matching classes into an `ImmutableArray` +- Processes ALL registrations in a single `Execute` method +- Generates a SINGLE output file containing: + - Main `AddAutorediServices()` method + - Group-specific methods (`AddAutorediServicesFirebase()`, etc.) +- Handles cross-assembly references by scanning referenced assemblies + +**Critical N-to-1 Pattern:** +```csharp +// Many inputs (individual service registrations) +var classDeclarations = context.SyntaxProvider + .CreateSyntaxProvider(...) + .Collect(); // <-- Aggregates N items + +// One output (single extension method file) +context.RegisterSourceOutput(compilationAndClasses, + (spc, source) => Execute(source.Left, source.Right, spc)); +``` + +### Flowgen's Current Architecture + +```mermaid +flowchart TD + A[Flow.Create] --> B[ForAttribute] + B --> C[Where - optional filter] + C --> D[Select - transform to model] + D --> E[Emit - generate per-item] + E --> F[And - chain another pipeline] + F --> B + E --> G[Build] + G --> H[Initialize] +``` + +**Key Characteristics:** +- Fluent, LINQ-like API +- Each pipeline processes items 1-to-1 +- `Emit` is called once per matched item +- Multiple pipelines can be chained with `.And()` +- Each pipeline generates output independently + +**Current Pipeline Pattern (1-to-1):** +```csharp +Flow.Create(context) + .ForAttribute("MyAttribute") + .Select((ctx, _) => new MyModel(ctx.Symbol.Name)) + .Emit((spc, model) => { + // Called once PER matching item + spc.AddSource($"{model.Name}.g.cs", code); + }) + .Build() + .Initialize(context); +``` + +## The N-to-1 Gap + +### Problem Statement + +Flowgen's current design generates **one output per input**. Autoredi requires **one output from many inputs** (aggregating all service registrations into a single extension method class). + +### Current Flowgen Limitations + +1. **No `.Collect()` equivalent**: Flowgen doesn't expose a way to aggregate all matched items before emission +2. **Per-item emission only**: The `Emit` action receives individual models, not collections +3. **No aggregation stage**: Missing a pipeline stage between `Select` and `Emit` that would allow collecting items + +### Why This Matters for Autoredi + +Autoredi generates code like this: + +```csharp +public static class AutorediExtensions +{ + // Aggregates ALL services into one method + public static IServiceCollection AddAutorediServices(this IServiceCollection services) + { + // Calls all group methods + services.AddAutorediServicesFirebase(); + services.AddAutorediServicesAccount(); + services.AddAutorediServicesDefault(); + return services; + } + + // Group method containing multiple registrations + public static IServiceCollection AddAutorediServicesFirebase(this IServiceCollection services) + { + services.AddSingleton(); + services.AddTransient(); + services.AddSingleton(); + return services; + } + + // ... more groups +} +``` + +This requires knowing about ALL registrations at emission time, not processing them individually. + +## Proposed Solutions + +### Option 1: Extend Flowgen with `.Collect()` and `.EmitAll()` (Recommended) + +Add N-to-1 aggregation capabilities directly to Flowgen: + +```csharp +// New API design for Flowgen +Flow.Create(context) + .ForAttribute("Autoredi") + .Select((ctx, _) => ExtractRegistration(ctx)) + .Collect() // NEW: Aggregate all items + .EmitAll((spc, registrations) => { // NEW: Emit from collection + // registrations is ImmutableArray + var code = GenerateExtensionMethods(registrations); + spc.AddSource("AutorediExtensions.g.cs", code); + }) + .Build() + .Initialize(context); +``` + +**Implementation in Flowgen:** + +```csharp +// New PipelineCollect stage +public sealed class PipelineCollect +{ + private readonly IncrementalGeneratorInitializationContext? _context; + private readonly FlowBuilder _builder; + private readonly string _attributeName; + private readonly bool _useMetadataName; + private readonly Func? _attrSelector; + + internal PipelineCollect(...) + { + // Store configuration + } + + /// + /// Emits source code from a collection of all aggregated models. + /// + public PipelineOutput> EmitAll( + Action> emitAction) + { + return new PipelineOutput>( + _context, _builder, + CollectAndTransform, // Transform that aggregates + _attributeName, _useMetadataName, + emitAction, + isImplementation: false); + } + + private ImmutableArray CollectAndTransform( + IncrementalValuesProvider provider, + IncrementalGeneratorInitializationContext context) + { + // Use Roslyn's Collect() to aggregate + var collected = provider.Collect(); + + // Register source output with the collected array + context.RegisterSourceOutput(collected, (spc, items) => { + // This will be handled by EmitAll's action + }); + + return collected; + } +} +``` + +**Pros:** +- Native Flowgen support for N-to-1 scenarios +- Consistent with existing fluent API +- Enables many other aggregation use cases +- Maintains incremental generation benefits + +**Cons:** +- Requires modifying Flowgen +- More complex implementation + +### Option 2: Hybrid Approach (Autoredi uses Flowgen + Raw Roslyn) + +Keep the N-to-1 aggregation in raw Roslyn while using Flowgen for other features: + +```csharp +[Generator] +public sealed class AutorediGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + // Use Flowgen for individual service extraction + var registrations = Flow.Create(context) + .ForAttribute("Autoredi") + .Select((ctx, _) => ExtractService(ctx)) + .Build() + .ToProvider(); // NEW: Expose the provider without registering output + + // Use raw Roslyn for aggregation + var collected = registrations.Collect(); + + context.RegisterSourceOutput(collected, (spc, services) => { + GenerateExtensionMethods(spc, services); + }); + } +} +``` + +**Required Flowgen Enhancement:** +Add ability to get the provider without registering output: + +```csharp +public IncrementalValuesProvider ToProvider() +{ + // Return the configured provider for external use + return _provider; +} +``` + +**Pros:** +- Minimal changes to Flowgen +- Flexible for complex scenarios + +**Cons:** +- Mixes two patterns (less elegant) +- Loses some of Flowgen's encapsulation benefits + +### Option 3: Custom Aggregation Model in Autoredi + +Use Flowgen's per-item emission but implement custom aggregation: + +```csharp +[Generator] +public sealed class AutorediGenerator : IIncrementalGenerator +{ + // Static collection to accumulate registrations across emission calls + private static readonly List _registrations = new(); + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + Flow.Create(context) + .ForAttribute("Autoredi") + .Select((ctx, _) => ExtractService(ctx)) + .Emit((spc, model) => { + // Accumulate in static list + _registrations.Add(model); + }) + .WithPostInitialization(ctx => { + // Generate final output after all items processed + GenerateExtensionMethods(ctx, _registrations.ToImmutableArray()); + _registrations.Clear(); + }) + .Build() + .Initialize(context); + } +} +``` + +**Pros:** +- Works with current Flowgen +- No Flowgen modifications needed + +**Cons:** +- Static state is problematic for incremental generation +- Race conditions possible +- Breaks incremental compilation model +- Not thread-safe + +## Recommendation: Option 1 - Extend Flowgen + +### Rationale + +1. **Architectural Alignment**: N-to-1 is a common pattern in source generators (configuration aggregation, registration collections, etc.) +2. **API Consistency**: Extending Flowgen maintains the fluent API philosophy +3. **Reusability**: Other generators will benefit from `.Collect()` and `.EmitAll()` +4. **Performance**: Proper integration with Roslyn's incremental pipeline + +### Implementation Plan for Flowgen Extensions + +#### Phase 1: Add `.Collect()` Stage + +```csharp +public sealed class PipelineCollect +{ + private readonly IncrementalGeneratorInitializationContext? _context; + private readonly FlowBuilder _builder; + private readonly IncrementalValuesProvider _provider; + + internal PipelineCollect( + IncrementalGeneratorInitializationContext? context, + FlowBuilder builder, + IncrementalValuesProvider provider) + { + _context = context; + _builder = builder; + _provider = provider; + } + + /// + /// Emits source code from a collection of all aggregated models. + /// + /// Action receiving the full collection of models. + /// A PipelineOutput for chaining. + public PipelineOutput> EmitAll( + Action> emitAction) + { + return new PipelineOutput>( + _context, _builder, _provider, emitAction, isCollect: true); + } +} +``` + +#### Phase 2: Modify PipelineOutput for Collection Support + +```csharp +public sealed class PipelineOutput +{ + // ... existing fields ... + private readonly bool _isCollect; + private readonly IncrementalValuesProvider? _provider; + + // Constructor for collection-based output + internal PipelineOutput( + IncrementalGeneratorInitializationContext? context, + FlowBuilder builder, + IncrementalValuesProvider provider, + Action emitAction, + bool isCollect) + { + _builder = builder; + _emitAction = emitAction; + _isCollect = isCollect; + _provider = provider; + + if (context.HasValue && isCollect) + { + RegisterCollectPipeline(context.Value, provider, emitAction); + } + } + + private void RegisterCollectPipeline( + IncrementalGeneratorInitializationContext context, + IncrementalValuesProvider provider, + Action emitAction) + { + _builder.AddPipeline(ctx => + { + // For collection, TModel is actually ImmutableArray + var collected = provider.Collect(); + ctx.RegisterSourceOutput(collected, (spc, items) => + { + emitAction(spc, items); + }); + }); + } +} +``` + +#### Phase 3: Add Extension Methods to PipelineTransform + +```csharp +public sealed class PipelineTransform +{ + // ... existing methods ... + + /// + /// Collects all models into an array before emission. + /// + /// A PipelineCollect for aggregated emission. + public PipelineCollect Collect() + { + // Create the provider and return collect stage + var provider = CreateProvider(); + return new PipelineCollect(_context, _builder, provider); + } +} +``` + +## Autoredi Rearchitecture with Extended Flowgen + +### New Autoredi Implementation + +```csharp +[Generator] +public sealed class AutorediGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + Flow.Create(context) + // Extract individual service registrations + .ForAttributeWithMetadataName( + "Autoredi.Attributes.AutorediAttribute") + .Select((ctx, ct) => ExtractRegistration(ctx, ct)) + // Collect all registrations into one + .Collect() + // Generate single extension method file + .EmitAll((spc, registrations) => GenerateExtensionMethods(spc, registrations)) + .Build() + .Initialize(context); + } + + private static ServiceRegistration ExtractRegistration( + GeneratorAttributeSyntaxContext ctx, + CancellationToken ct) + { + // Extract service info from attribute + var classSymbol = (INamedTypeSymbol)ctx.TargetSymbol; + var attribute = ctx.Attributes[0]; + + return new ServiceRegistration( + ClassName: classSymbol.ToDisplayString(), + Lifetime: (int)attribute.ConstructorArguments[0].Value!, + InterfaceName: GetInterfaceName(attribute), + ServiceKey: GetServiceKey(attribute), + Group: GetGroup(attribute), + Priority: GetPriority(attribute) + ); + } + + private static void GenerateExtensionMethods( + SourceProductionContext spc, + ImmutableArray registrations) + { + // Group registrations + var grouped = registrations + .GroupBy(r => r.Group ?? "Default") + .ToDictionary(g => g.Key, g => g.ToList()); + + // Generate code + var code = new StringBuilder(); + code.AppendLine("// "); + code.AppendLine("using Microsoft.Extensions.DependencyInjection;"); + code.AppendLine(); + code.AppendLine("namespace Autoredi.Generated;"); + code.AppendLine(); + code.AppendLine("public static class AutorediExtensions"); + code.AppendLine("{"); + + // Generate main method + GenerateMainMethod(code, grouped.Keys); + + // Generate group methods + foreach (var group in grouped) + { + GenerateGroupMethod(code, group.Key, group.Value); + } + + code.AppendLine("}"); + + spc.AddSource("AutorediExtensions.g.cs", code.ToString()); + } +} + +public record ServiceRegistration( + string ClassName, + int Lifetime, + string? InterfaceName, + string? ServiceKey, + string? Group, + int Priority +); +``` + +### Benefits + +1. **Cleaner Code**: ~50% reduction in boilerplate +2. **Type Safety**: Strongly-typed models instead of syntax manipulation +3. **Testability**: Models are easy to test +4. **Maintainability**: Fluent API is more readable +5. **Performance**: Still uses incremental generation + +## Migration Steps + +### Step 1: Extend Flowgen (in /usr/local/repo/Flowgen) + +1. Add `PipelineCollect` class +2. Add `Collect()` method to `PipelineTransform` +3. Add `EmitAll()` method to `PipelineCollect` +4. Update `PipelineOutput` to handle collection +5. Add unit tests +6. Update documentation + +### Step 2: Update Autoredi.Generators + +1. Add Flowgen package reference +2. Create `ServiceRegistration` model +3. Rewrite `AutorediGenerator` using Flowgen fluent API +4. Port diagnostic validation logic +5. Update tests + +### Step 3: Validation + +1. All existing tests pass +2. Generated code is identical (or improved) +3. Performance benchmarks show no regression +4. Cross-assembly references work correctly + +## Files to Modify + +### Flowgen Changes +``` +/usr/local/repo/Flowgen/src/Flowgen/ +├── Flow.cs (add Collect() method, PipelineCollect class) +└── docs/README.md (document N-to-1 pattern) + +/usr/local/repo/Flowgen/tests/Unit/Flowgen.Tests/ +└── FlowTests.cs (add tests for Collect/EmitAll) +``` + +### Autoredi Changes +``` +src/Autoredi.Generators/ +├── Autoredi.Generators.csproj (add Flowgen reference) +├── AutorediGenerator.cs (rewrite with Flowgen) +├── Models/ +│ └── ServiceRegistration.cs (new) +└── Extraction/ + └── ServiceRegistrationExtractor.cs (new) +``` + +## Success Criteria + +- [ ] Flowgen supports `.Collect()` and `.EmitAll()` operations +- [ ] Autoredi uses Flowgen for all source generation +- [ ] All existing Autoredi tests pass without modification +- [ ] Generated code is functionally equivalent +- [ ] No performance regression in benchmarks +- [ ] Cross-assembly service discovery works correctly +- [ ] Grouped registration works correctly +- [ ] Diagnostic validation works correctly From 0d8330e4665107bac4246d3a45d36189ccea0996 Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 13:47:10 -0400 Subject: [PATCH 5/6] docs: refresh ongoing plan --- codex-plan.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/codex-plan.md b/codex-plan.md index a7ff654..994cbc4 100644 --- a/codex-plan.md +++ b/codex-plan.md @@ -2,14 +2,14 @@ ## Context - Track actions I (the assistant) take so the human partner can see what needs to happen next. -- Focus areas so far: understand Autoredi's generator + Flowgen upgrade path, and note where the Flowgen skill instructions live. +- Focus areas so far: understand Autoredi's generator + Flowgen upgrade path, note where the Flowgen skill instructions live, and capture Autoredi usage guidance in a dedicated skill. ## Flowgen skill notes -- AGENTS instructions now have a symlink at `/Users/omoi/Developer/@repo/_dev/Autoredi/docs/AGENTS-link.md` so I can re-open the instructions easily. -- The Flowgen skill referenced there is located at `/usr/local/repo/flowgen-source-generator/SKILL.md` (plus the global `~/.codex/skills/flowgen-source-generators/SKILL.md`). It highlights Flowgen v0.7+ features such as `context.Flow()`/`Flow.Create(context)` starting points, `AttributeContext` in `.Select(...)`, and the existing `.Collect()`/`.EmitAll()` pipeline for N-to-1 outputs. +- The Flowgen skill referenced in AGENTS is located at `/usr/local/repo/flowgen-source-generator/SKILL.md` (plus the global `~/.codex/skills/flowgen-source-generators/SKILL.md`). It highlights Flowgen v0.7+ features such as `context.Flow()`/`Flow.Create(context)` starting points, `AttributeContext` in `.Select(...)`, and the existing `.Collect()`/`.EmitAll()` pipeline for N-to-1 outputs. ## Work items -1. [ ] Upgrade `Autoredi.Generators` to Flowgen 0.7.0, switch the pipeline to `context.Flow()` and the new `AttributeContext` extractors, and keep the aggregated registration builder intact (this change is currently in progress). -2. [ ] Wait for the next set of instructions from the user once this groundwork is ready; the plan file will keep evolving as more tasks land here. +1. [x] Upgrade `Autoredi.Generators` to Flowgen 0.7.0, switch the pipeline to `context.Flow()` and the new `AttributeContext` extractors, and keep the aggregated registration builder intact. +2. [x] Capture Autoredi-focused knowledge in a new skill at `/Users/omoi/.codex/skills/autoredi/SKILL.md` and reference it from AGENTS. +3. [ ] Keep waiting for the next set of instructions from the user once this groundwork is ready; update this plan accordingly. *This file is git-ignored because it is meant for live collaboration notes only.* From 76d8b4a313458060eda3912cc0c96c9ab7d3ae79 Mon Sep 17 00:00:00 2001 From: Koddek Date: Fri, 6 Feb 2026 14:06:28 -0400 Subject: [PATCH 6/6] bump version to 0.4.0 --- src/Autoredi/Autoredi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Autoredi/Autoredi.csproj b/src/Autoredi/Autoredi.csproj index 7d04968..725b9bb 100644 --- a/src/Autoredi/Autoredi.csproj +++ b/src/Autoredi/Autoredi.csproj @@ -3,7 +3,7 @@ net10.0 Autoredi - 0.3.0 + 0.4.0 true true