Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ This file defines how AI agents work in this solution.
- Solution root: `.` (`DotPilot.slnx`)
- Projects or modules with local `AGENTS.md` files:
- `DotPilot`
- `DotPilot.Core`
- `DotPilot.Runtime`
- `DotPilot.ReleaseTool`
- `DotPilot.Tests`
- `DotPilot.UITests`
Expand Down Expand Up @@ -136,13 +138,16 @@ For this app:
- coverage uses the `coverlet.collector` integration on `DotPilot.Tests` with the repo runsettings file to keep generated Uno artifacts out of the coverage path
- desktop release publishing uses `dotnet publish DotPilot/DotPilot.csproj -c Release -f net10.0-desktop`; the validation workflow stays focused on build and automated tests, while the release workflow owns desktop publish outputs for macOS, Windows, and Linux
- `LangVersion` is pinned to `latest` at the root
- prefer the newest stable `.NET 10` and `C#` language features that are supported by the pinned SDK and do not weaken readability, determinism, or analyzability
- the repo-root lowercase `.editorconfig` is the source of truth for formatting, naming, style, and analyzer severity
- local and CI build commands must pass `-warnaserror`; warnings are not an acceptable "green" build state in this repository
- quality gates should prefer analyzer-backed build failures over separate one-off CI tools; for overloaded methods and maintainability drift, enable build-time analyzers such as `CA1502` instead of adding a formatting-only gate
- `Directory.Build.props` owns the shared analyzer and warning policy for future projects
- `Directory.Packages.props` owns centrally managed package versions
- `global.json` pins the .NET SDK and Uno SDK version used by the app and tests
- `DotPilot/DotPilot.csproj` keeps `GenerateDocumentationFile=true` with `CS1591` suppressed so `IDE0005` stays enforceable in CI across all target frameworks without inventing command-line-only build flags
- architecture work must keep a vertical-slice shape: each feature owns its contracts, orchestration, and tests behind clear boundaries instead of growing a shared horizontal service layer
- keep the Uno app project presentation-only; domain, runtime host, orchestration, integrations, and persistence code must live in separate class-library projects so UI composition does not mix with feature implementation
- GitHub Actions workflows must use descriptive names and filenames that reflect their purpose; do not use a generic `ci.yml` catch-all because build validation and release automation are separate operator flows
- GitHub Actions must be split into at least one validation workflow for normal builds/tests and one release workflow for CI-driven version resolution, release-note generation, desktop publishing, and GitHub Release publication
- the release workflow must run automatically on pushes to `main`, build desktop apps, and publish the GitHub Release without requiring a manual dispatch
Expand Down Expand Up @@ -259,16 +264,20 @@ Local `AGENTS.md` files may tighten these values, but they must not loosen them
- Tests must prove the real user flow or caller-visible system flow, not only internal implementation details.
- Tests should be as realistic as possible and exercise the system through real flows, contracts, and dependencies.
- Tests must cover positive flows, negative flows, edge cases, and unexpected paths from multiple relevant angles when the behaviour can fail in different ways.
- All caller-visible feature flows must have API or integration-style automated coverage through public contracts; structure-only unit tests are not enough for this repository.
- Prefer integration, API, and UI tests over isolated unit tests when behaviour crosses boundaries.
- Do not use mocks, fakes, stubs, or service doubles in verification.
- Exercise internal and external dependencies through real containers, test instances, or sandbox environments that match the real contract.
- Flaky tests are failures. Fix the cause.
- Because CI does not guarantee Codex, Claude Code, or GitHub Copilot availability, keep a deterministic test AI client in-repo so core agent flows stay testable without external provider CLIs.
- Tests that require real Codex, Claude Code, or GitHub Copilot toolchains must run only when the corresponding toolchain and auth are available; their absence is an environment condition, not a reason to block the provider-independent test baseline.
- Changed production code MUST reach at least 80% line coverage, and at least 70% branch coverage where branch coverage is available.
- Critical flows and public contracts MUST reach at least 90% line coverage with explicit success and failure assertions.
- Repository or module coverage must not decrease without an explicit written exception. Coverage after the change must stay at least at the previous baseline or improve.
- Coverage is for finding gaps, not gaming a number. Coverage numbers do not replace scenario coverage or user-flow verification.
- The task is not done until the full relevant test suite is green, not only the newly added tests.
- UI tests are mandatory for this repository and must run in normal agent verification; missing local browser-driver setup is a harness bug to fix, not a reason to skip the suite.
- UI coverage must validate complete end-to-end operator flows and also assert the presence and behavior of each interactive element introduced by a feature.
- GitHub Actions PR validation is mandatory for every PR and must enforce the real repo verification path so test failures are caught in CI, not only locally.
- GitHub Actions PR validation must run full automated test verification, especially the real UI suite; build-only or smoke-only checks are not an acceptable substitute for pull-request gating.
- GitHub Actions validation must also produce downloadable app artifacts for macOS, Windows, and Linux so every PR and mainline run has test results plus installable build outputs.
Expand Down Expand Up @@ -322,6 +331,7 @@ Ask first:

- Follow the canonical MCAF tutorial when bootstrapping or upgrading the agent workflow.
- Commit cohesive code-change batches promptly while debugging, especially before switching focus or starting long verification runs, so the branch state stays inspectable and pushable.
- After opening or updating a PR, create a fresh working branch before continuing with the next slice of work so follow-up changes do not pile onto the already-reviewed branch.
- Keep the root `AGENTS.md` at the repository root.
- Keep the repo-local agent skill directory limited to current `mcaf-*` skills.
- Keep the solution file name cased as `DotPilot.slnx`.
Expand Down
40 changes: 40 additions & 0 deletions DotPilot.Core/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# AGENTS.md

Project: `DotPilot.Core`
Stack: `.NET 10`, class library, feature-aligned contracts and provider-independent runtime foundations

## Purpose

- This project owns non-UI contracts, typed identifiers, and feature slices that must stay independent from the Uno presentation host.
- It provides the stable public shapes for runtime, orchestration, providers, and shell configuration so UI and future runtime implementations can evolve without circular coupling.

## Entry Points

- `DotPilot.Core.csproj`
- `Features/ApplicationShell/AppConfig.cs`
- `Features/RuntimeFoundation/*`

## Boundaries

- Keep this project free of `Uno Platform`, XAML, brushes, and page/view-model concerns.
- Organize code by vertical feature slice, not by shared horizontal folders such as generic `Services` or `Helpers`.
- Prefer stable contracts, typed identifiers, and public interfaces here; concrete runtime integrations can live in separate libraries.
- Keep provider-independent testing seams real and deterministic so CI can validate core flows without external CLIs.

## Local Commands

- `build-core`: `dotnet build DotPilot.Core/DotPilot.Core.csproj`
- `test-core`: `dotnet test DotPilot.Tests/DotPilot.Tests.csproj --filter FullyQualifiedName~RuntimeFoundation`

## Applicable Skills

- `mcaf-dotnet`
- `mcaf-dotnet-features`
- `mcaf-testing`
- `mcaf-solid-maintainability`
- `mcaf-architecture-overview`

## Local Risks Or Protected Areas

- These contracts will become shared dependencies across future slices, so naming drift or unclear boundaries will amplify quickly.
- Avoid baking provider-specific assumptions into the core runtime contracts unless an ADR or feature spec explicitly requires them.
9 changes: 9 additions & 0 deletions DotPilot.Core/DotPilot.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

</Project>
6 changes: 6 additions & 0 deletions DotPilot.Core/Features/ApplicationShell/AppConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DotPilot.Core.Features.ApplicationShell;

public sealed record AppConfig
{
public string? Environment { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DotPilot.Core.Features.RuntimeFoundation;

public interface IAgentRuntimeClient
{
ValueTask<AgentTurnResult> ExecuteAsync(AgentTurnRequest request, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DotPilot.Core.Features.RuntimeFoundation;

public interface IRuntimeFoundationCatalog
{
RuntimeFoundationSnapshot GetSnapshot();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace DotPilot.Core.Features.RuntimeFoundation;

public sealed record RuntimeSliceDescriptor(
int IssueNumber,
string IssueLabel,
string Name,
string Summary,
RuntimeSliceState State);

public sealed record ProviderToolchainStatus(
string DisplayName,
string CommandName,
ProviderConnectionStatus Status,
string StatusSummary,
bool RequiresExternalToolchain);

public sealed record RuntimeFoundationSnapshot(
string EpicLabel,
string Summary,
string DeterministicClientName,
string DeterministicProbePrompt,
IReadOnlyList<RuntimeSliceDescriptor> Slices,
IReadOnlyList<ProviderToolchainStatus> Providers);

public sealed record AgentTurnRequest(
SessionId SessionId,
AgentProfileId AgentProfileId,
string Prompt,
AgentExecutionMode Mode);

public sealed record AgentTurnResult(
string Summary,
SessionPhase NextPhase,
ApprovalState ApprovalState,
IReadOnlyList<string> ProducedArtifacts);
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Globalization;

namespace DotPilot.Core.Features.RuntimeFoundation;

public readonly record struct WorkspaceId(Guid Value)
{
public static WorkspaceId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}

public readonly record struct AgentProfileId(Guid Value)
{
public static AgentProfileId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}

public readonly record struct SessionId(Guid Value)
{
public static SessionId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}

public readonly record struct FleetId(Guid Value)
{
public static FleetId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}

public readonly record struct ProviderId(Guid Value)
{
public static ProviderId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}

public readonly record struct ModelRuntimeId(Guid Value)
{
public static ModelRuntimeId New() => new(Guid.CreateVersion7());

public override string ToString() => Value.ToString("N", CultureInfo.InvariantCulture);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace DotPilot.Core.Features.RuntimeFoundation;

public static class RuntimeFoundationIssues
{
private const string IssuePrefix = "#";

public const int EmbeddedAgentRuntimeHostEpic = 12;
public const int DomainModel = 22;
public const int CommunicationContracts = 23;
public const int EmbeddedOrleansHost = 24;
public const int AgentFrameworkRuntime = 25;

public static string FormatIssueLabel(int issueNumber) => string.Concat(IssuePrefix, issueNumber);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
namespace DotPilot.Core.Features.RuntimeFoundation;

public enum SessionPhase
{
Plan,
Execute,
Review,
Paused,
Completed,
Failed,
}

public enum ProviderConnectionStatus
{
Available,
Unavailable,
}

public enum ApprovalState
{
NotRequired,
Pending,
Approved,
Rejected,
}

public enum RuntimeSliceState
{
Planned,
Sequenced,
ReadyForImplementation,
}

public enum AgentExecutionMode
{
Plan,
Execute,
Review,
}
40 changes: 40 additions & 0 deletions DotPilot.Runtime/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# AGENTS.md

Project: `DotPilot.Runtime`
Stack: `.NET 10`, class library, provider-independent runtime services and diagnostics

## Purpose

- This project owns non-UI runtime implementations that sit behind the contracts in `DotPilot.Core`.
- It is the first landing zone for deterministic test clients, runtime probes, and later embedded-host integrations so the Uno app stays focused on presentation and startup composition.

## Entry Points

- `DotPilot.Runtime.csproj`
- `Features/RuntimeFoundation/*`
- `Features/HttpDiagnostics/DebugHttpHandler.cs`

## Boundaries

- Keep this project free of `Uno Platform`, XAML, and page/view-model logic.
- Implement feature slices against `DotPilot.Core` contracts instead of reaching back into the app project.
- Prefer deterministic runtime behavior and environment probing here so tests can exercise real flows without mocks.
- Keep external-provider assumptions soft: absence of Codex, Claude Code, or GitHub Copilot in CI must not break the provider-independent baseline.

## Local Commands

- `build-runtime`: `dotnet build DotPilot.Runtime/DotPilot.Runtime.csproj`
- `test-runtime`: `dotnet test DotPilot.Tests/DotPilot.Tests.csproj --filter FullyQualifiedName~RuntimeFoundation`

## Applicable Skills

- `mcaf-dotnet`
- `mcaf-dotnet-features`
- `mcaf-testing`
- `mcaf-solid-maintainability`
- `mcaf-architecture-overview`

## Local Risks Or Protected Areas

- Runtime services introduced here will become composition roots for later Orleans and Agent Framework work, so keep boundaries explicit.
- Toolchain probing must stay deterministic and side-effect free; do not turn startup checks into live external calls.
13 changes: 13 additions & 0 deletions DotPilot.Runtime/DotPilot.Runtime.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\DotPilot.Core\DotPilot.Core.csproj" />
</ItemGroup>

</Project>
60 changes: 60 additions & 0 deletions DotPilot.Runtime/Features/HttpDiagnostics/DebugHttpHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#if DEBUG
using System.Diagnostics;
using System.Globalization;
using System.Text;
#endif

namespace DotPilot.Runtime.Features.HttpDiagnostics;

public sealed class DebugHttpHandler(HttpMessageHandler? innerHandler = null)
: DelegatingHandler(innerHandler ?? new HttpClientHandler())
{
#if DEBUG
private const string UnsuccessfulApiCallMessage = "Unsuccessful API call";
private const string RequestUriFormat = "{0} ({1})";
private const string HeaderFormat = "{0}: {1}";
private const string HeaderSeparator = ", ";
private static readonly CompositeFormat RequestUriCompositeFormat = CompositeFormat.Parse(RequestUriFormat);
private static readonly CompositeFormat HeaderCompositeFormat = CompositeFormat.Parse(HeaderFormat);
#endif

protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
#if DEBUG
if (!response.IsSuccessStatusCode)
{
Trace.WriteLine(UnsuccessfulApiCallMessage);

if (request.RequestUri is not null)
{
Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, RequestUriCompositeFormat, request.RequestUri, request.Method));
}

foreach (var header in request.Headers)
{
Trace.WriteLine(string.Format(
CultureInfo.InvariantCulture,
HeaderCompositeFormat,
header.Key,
string.Join(HeaderSeparator, header.Value)));
}

if (request.Content is null)
{
return response;
}

var content = await request.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrWhiteSpace(content))
{
Trace.WriteLine(content);
}
}
#endif

return response;
}
}
Loading