diff --git a/.gitignore b/.gitignore index 9ee38a0..1adf3f8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,9 @@ packages/ .DS_Store Thumbs.db .claude/ + +.tmp-gh-*.ps1 + +.tmp-venv*/ + +TestResults/ diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 279e37b..351c69e 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -112,28 +112,28 @@ ### CI Quality (CIQUAL) -- [ ] **CIQUAL-01**: CI workflow runs `dotnet test` on every push/PR — not just build -- [ ] **CIQUAL-02**: Coverlet coverage collected in CI — TRX report + XML coverage artifact uploaded -- [ ] **CIQUAL-03**: Coverage badge in README showing current line coverage % +- [x] **CIQUAL-01**: CI workflow runs `dotnet test` on every push/PR — not just build +- [x] **CIQUAL-02**: Coverlet coverage collected in CI — TRX report + XML coverage artifact uploaded +- [x] **CIQUAL-03**: Coverage badge in README showing current line coverage % ### Test Coverage (TESTCOV) -- [ ] **TESTCOV-01**: `AnalyzingState` has dedicated xUnit test class (≥ 3 [Fact] tests covering Happy Path, Claude failure, and cancellation) -- [ ] **TESTCOV-02**: `BranchingState` has dedicated xUnit test class (≥ 3 [Fact] tests) -- [ ] **TESTCOV-03**: `CommittingState` has dedicated xUnit test class (≥ 3 [Fact] tests) -- [ ] **TESTCOV-04**: `DocumentingState` has dedicated xUnit test class (≥ 3 [Fact] tests) -- [ ] **TESTCOV-05**: `EditingState` has dedicated xUnit test class (≥ 3 [Fact] tests) -- [ ] **TESTCOV-06**: `PrCreatingState` has dedicated xUnit test class (≥ 3 [Fact] tests) +- [x] **TESTCOV-01**: `AnalyzingState` has dedicated xUnit test class (≥ 3 [Fact] tests covering Happy Path, Claude failure, and cancellation) +- [x] **TESTCOV-02**: `BranchingState` has dedicated xUnit test class (≥ 3 [Fact] tests) +- [x] **TESTCOV-03**: `CommittingState` has dedicated xUnit test class (≥ 3 [Fact] tests) +- [x] **TESTCOV-04**: `DocumentingState` has dedicated xUnit test class (≥ 3 [Fact] tests) +- [x] **TESTCOV-05**: `EditingState` has dedicated xUnit test class (≥ 3 [Fact] tests) +- [x] **TESTCOV-06**: `PrCreatingState` has dedicated xUnit test class (≥ 3 [Fact] tests) ### Checkpoint Hardening (CHKPT) -- [ ] **CHKPT-01**: `GsdWorkflowContext` (WorkflowModels.cs) includes `SchemaVersion` string property, serialized to checkpoint JSON -- [ ] **CHKPT-02**: `FileCheckpointStore.LoadAsync` checks `SchemaVersion` on load — logs warning and returns null (starts fresh) on version mismatch +- [x] **CHKPT-01**: `GsdWorkflowContext` (WorkflowModels.cs) includes `SchemaVersion` string property, serialized to checkpoint JSON +- [x] **CHKPT-02**: `FileCheckpointStore.LoadAsync` checks `SchemaVersion` on load — logs warning and returns null (starts fresh) on version mismatch ### Portfolio Polish (POLISH) -- [ ] **POLISH-01**: GitHub topics applied to all CAS flagship repos (gsd-orchestrator, Promptimprover, autogen) — verified via `gh repo view --json repositoryTopics` -- [ ] **POLISH-02**: OgeonX-Ai personal profile README exists in `OgeonX-Ai/.github` repo at `profile/README.md`, linking to Coding-Autopilot-System org and highlighting gsd-orchestrator, Promptimprover, autogen as system +- [x] **POLISH-01**: GitHub topics applied to all CAS flagship repos (gsd-orchestrator, Promptimprover, autogen) — verified via `gh repo view --json repositoryTopics` +- [x] **POLISH-02**: OgeonX-Ai personal profile README exists in `OgeonX-Ai/.github` repo at `profile/README.md`, linking to Coding-Autopilot-System org and highlighting gsd-orchestrator, Promptimprover, autogen as system ## v1 Deferred (still out of scope for v2) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a0b9fc0..6acd2f2 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -458,8 +458,8 @@ Plans: **Plans:** 2 plans Plans: -- [ ] 17-01-PLAN.md — Add `dotnet test` step to ci.yml with Coverlet XML + TRX output, upload coverage artifact (CIQUAL-01, CIQUAL-02) -- [ ] 17-02-PLAN.md — Add coverage badge to README (shields.io from coverage.xml artifact) (CIQUAL-03) +- [x] 17-01-PLAN.md — Add `dotnet test` step to ci.yml with Coverlet XML + TRX output, upload coverage artifact (CIQUAL-01, CIQUAL-02) +- [x] 17-02-PLAN.md — Add coverage badge to README (shields.io from coverage.xml artifact) (CIQUAL-03) **Success Criteria:** - PR checks page shows a passing "test" step alongside the existing "build" step @@ -480,9 +480,9 @@ Plans: **Plans:** 3 plans Plans: -- [ ] 18-01-PLAN.md — Write AnalyzingStateTests.cs, BranchingStateTests.cs, EditingStateTests.cs (Wave 1 — read-heavy states) (TESTCOV-01, TESTCOV-02, TESTCOV-05) -- [ ] 18-02-PLAN.md — Write CommittingStateTests.cs, DocumentingStateTests.cs, PrCreatingStateTests.cs (Wave 2 — write-heavy states) (TESTCOV-03, TESTCOV-04, TESTCOV-06) -- [ ] 18-03-PLAN.md — Add SchemaVersion to GsdWorkflowContext in WorkflowModels.cs; add version check to FileCheckpointStore.LoadAsync; write 2 unit tests verifying mismatch handling (CHKPT-01, CHKPT-02) +- [x] 18-01-PLAN.md — Write AnalyzingStateTests.cs, BranchingStateTests.cs, EditingStateTests.cs (Wave 1 — read-heavy states) (TESTCOV-01, TESTCOV-02, TESTCOV-05) +- [x] 18-02-PLAN.md — Write CommittingStateTests.cs, DocumentingStateTests.cs, PrCreatingStateTests.cs (Wave 2 — write-heavy states) (TESTCOV-03, TESTCOV-04, TESTCOV-06) +- [x] 18-03-PLAN.md — Add SchemaVersion to GsdWorkflowContext in WorkflowModels.cs; add version check to FileCheckpointStore.LoadAsync; write 2 unit tests verifying mismatch handling (CHKPT-01, CHKPT-02) **Success Criteria:** - `dotnet test` runs 53+ tests (35 existing + 18 new state tests + 2 checkpoint tests) all green @@ -503,8 +503,8 @@ Plans: **Plans:** 2 plans Plans: -- [ ] 19-01-PLAN.md — Apply GitHub topics to gsd-orchestrator, Promptimprover, autogen via `gh repo edit --add-topic`; verify via `gh repo view --json repositoryTopics` (POLISH-01) -- [ ] 19-02-PLAN.md — Create/update OgeonX-Ai personal profile README at OgeonX-Ai/.github/profile/README.md — links to Coding-Autopilot-System org, highlights gsd-orchestrator/Promptimprover/autogen as a system (POLISH-02) +- [x] 19-01-PLAN.md — Apply GitHub topics to gsd-orchestrator, Promptimprover, autogen via `gh repo edit --add-topic`; verify via `gh repo view --json repositoryTopics` (POLISH-01) +- [x] 19-02-PLAN.md — Create/update OgeonX-Ai personal profile README at OgeonX-Ai/.github/profile/README.md — links to Coding-Autopilot-System org, highlights gsd-orchestrator/Promptimprover/autogen as a system (POLISH-02) **Success Criteria:** - `gh repo view Coding-Autopilot-System/gsd-orchestrator --json repositoryTopics` returns at least 5 topics including `autonomous-agent`, `dotnet`, `state-machine` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e09ae37 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env +WORKDIR /App + +# Copy everything +COPY . ./ +# Restore as distinct layers +RUN dotnet restore +# Build and publish a release +RUN dotnet publish -c Release -o out + +# Build runtime image +FROM mcr.microsoft.com/dotnet/aspnet:10.0 +WORKDIR /App +COPY --from=build-env /App/out . +ENTRYPOINT ["dotnet", "gsd-orchestrator.dll"] diff --git a/README.md b/README.md index 55c5745..d6107ef 100644 --- a/README.md +++ b/README.md @@ -1,234 +1,31 @@ -# GSD Orchestrator +# ?? GSD Orchestrator: The Autonomous Issue-to-PR Engine -[![CI](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml/badge.svg)](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml) [![CodeQL](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/codeql.yml/badge.svg)](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/codeql.yml) +![Visual Diagram](docs/assets/concept.png) -Autonomous GitHub issue-to-PR engine. Point it at a real issue and it reads the -task, plans the work, creates a branch, edits code, validates the result, and -opens a pull request with durable workflow state. +![Build Status](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml/badge.svg) +![CodeQL](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/codeql.yml/badge.svg) +![Version](https://img.shields.io/badge/version-1.0.0--elite-blue) +![Stack](https://img.shields.io/badge/stack-.NET%2010%20%7C%20C%23-purple) -**Stack:** .NET 10 (C#) · GitHub MCP Server · Anthropic Claude · Polly +**GSD Orchestrator** is an elite, fully autonomous GitHub engine. Point it at a raw GitHub Issue, and it reads the task, plans the architecture, spins up an isolated branch, edits the code, validates the results, and opens a robust Pull Request. -[![CI](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml/badge.svg)](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml) -[![Tests](https://img.shields.io/badge/tests-35%20passing-brightgreen)](https://github.com/Coding-Autopilot-System/gsd-orchestrator/actions/workflows/ci.yml) -[![.NET 10](https://img.shields.io/badge/.NET-10-512BD4)](https://dotnet.microsoft.com/download/dotnet/10.0) -[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) +## ?? Elite Features +* **Zero-Touch Resolution**: Paste an issue URL, get a merged PR. +* **Anthropic Claude Integration**: Leverages frontier models for hyper-intelligent code synthesis. +* **GitHub MCP Server**: Uses the Model Context Protocol to seamlessly pull repo state, issues, and PR schemas. +* **Durable Workflow State**: Powered by Polly for insane resilience against network drops and rate limits. -Part of the [Coding-Autopilot-System](https://github.com/Coding-Autopilot-System) ecosystem: -[Promptimprover](https://github.com/Coding-Autopilot-System/Promptimprover) | [autogen](https://github.com/Coding-Autopilot-System/autogen) +## ? Quickstart +1. Ensure .NET 10 is installed. +2. Clone and build: + \\\ash + dotnet build + \\\ +3. Run the orchestrator against an issue: + \\\ash + dotnet run -- --issue-url https://github.com/org/repo/issues/1 + \\\ --- - -## Why This Repo Matters - -`gsd-orchestrator` is the execution-focused flagship in the portfolio. Its value is -not just "AI edits code." The stronger signal is the operational model around that: - -- state-machine controlled execution instead of a single opaque loop -- checkpoint and resume behavior for long-running workflows -- explicit validation gates before PR creation -- GitHub operations routed through MCP tooling rather than hard-coded scripts -- a design that can later sit behind a workstation bundle or a hosted control plane - -## Enterprise Proof Points - -- **Durability**: workflow state is checkpointed so interrupted runs can be resumed. -- **Guardrails**: validation blocks unsafe diffs, merge-conflict surprises, and weak test intent. -- **Operational separation**: GitHub tool access is mediated through MCP rather than being spread across ad hoc shell calls. -- **Auditability**: the lifecycle from issue to branch to PR is explicit and reproducible. - -See [docs/portfolio-proof.md](docs/portfolio-proof.md) for a concise reviewer-oriented summary. - -## How It Works - -```text -Issue -> Idle -> Triaging -> Analyzing -> Branching -> Editing -> TestGenerating -> Validating -> Committing -> PrCreating -> Reviewing -> Documenting -> Done -``` - -Actionable issues follow the full path. Non-actionable issues and `--triage` runs -exit after `Triaging`. The separate `--pr` mode enters at `Reviewing` and exits -after submitting its structured review. Each state uses GitHub MCP tools via stdio -to interact with GitHub and Claude to reason about what to do next. Checkpoints are -written to disk so an interrupted or failed run can be inspected and resumed. - -## State Machine - -```mermaid -stateDiagram-v2 - direction LR - [*] --> Idle - Idle --> Triaging - Triaging --> Analyzing: actionable issue - Triaging --> Done: non-actionable or --triage - Analyzing --> Branching - Branching --> Editing - Editing --> TestGenerating - TestGenerating --> Validating - Validating --> Committing - Validating --> Failed: blocking gate - Committing --> PrCreating - PrCreating --> Reviewing - Reviewing --> Documenting: issue mode - [*] --> Reviewing: --pr mode - Reviewing --> Done: PR-review mode - Documenting --> Done - Done --> [*] - Failed --> [*] -``` - -Any unhandled state exception also transitions the workflow to `Failed`. - -### State Responsibilities - -- **Idle** - Fetches repository metadata and full issue body from GitHub via MCP. -- **Triaging** - Classifies the issue, checks for duplicates, posts the triage result, and routes actionable issues to analysis or exits. -- **Analyzing** - Produces an implementation plan, branch intent, file targets, and test expectations. -- **Branching** - Creates or resumes the feature branch. -- **Editing** - Runs iterative edit loops and commits each changed file to the feature branch. -- **TestGenerating** - Generates or extends xUnit tests for eligible edited C# source files. -- **Validating** - Applies file-safety, merge-conflict, diff-size, test-intent, and generated-test structure checks. -- **Committing** - Confirms and records the latest commit on the feature branch. -- **PrCreating** - Creates or reuses the pull request for the work branch. -- **Reviewing** - Posts issue-mode reviewer guidance and requests reviewers, or submits a structured review in `--pr` mode. -- **Documenting** - Refreshes the MCP tool catalog and changelog on the default branch, then optionally auto-merges. -- **Done / Failed** - Terminal outcomes recorded by the state machine. - -## Component Topology - -```mermaid -flowchart LR - subgraph Orchestrator["GSD Orchestrator (.NET 10)"] - SM[GsdStateMachine] - MCP[McpStdioClient] - LLM[Anthropic.SDK] - CP[FileCheckpointStore] - end - - subgraph GitHub["GitHub"] - MCPS[github-mcp-server.exe] - GHAPI[GitHub API] - end - - subgraph Anthropic["Anthropic"] - CLAUDE[Claude API] - end - - subgraph Storage["Local Storage"] - CKPT[.gsd/state/] - end - - SM --> MCP - MCP -->|stdio| MCPS - MCPS --> GHAPI - SM --> LLM - LLM --> CLAUDE - SM --> CP - CP --> CKPT -``` - -## Prerequisites - -- Windows -- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) -- `github-mcp-server.exe` already included in the repo root -- A GitHub Personal Access Token with `repo` and `read:org` scopes -- An Anthropic API key - -## Setup - -```bash -git clone https://github.com/Coding-Autopilot-System/gsd-orchestrator.git -cd gsd-orchestrator -cp .env.example .env -``` - -Edit `.env` and set: - -```env -GITHUB_PERSONAL_ACCESS_TOKEN=ghp_... -ANTHROPIC_API_KEY=sk-ant-... -GSD_GITHUB_OWNER=Coding-Autopilot-System -GSD_GITHUB_REPO=gsd-orchestrator -GSD_REVIEWERS= -``` - -## Run The Orchestrator - -```bash -cd src/GsdOrchestrator -dotnet run -- --issue 42 -dotnet run -- --resume -``` - -On success: - -```text -✓ PR created: https://github.com/.../pull/N -✓ Docs updated: docs/github-mcp-tools.md, CHANGELOG.md - Workflow ID: -``` - -## Demo Review Path - -For a fast evaluation of the repo: - -1. Read this README for the control flow and operational model. -2. Read [docs/portfolio-proof.md](docs/portfolio-proof.md) for the concise reviewer summary. -3. Inspect `src/GsdOrchestrator/Workflows/States` for the state-machine structure. -4. Inspect the GitHub MCP startup scripts to see how local CLI use and orchestrator use are separated. - -## Use GitHub MCP Tools In AI CLIs - -The `github-mcp-server.exe` also runs as an HTTP server on `localhost:8765` and can -serve GitHub tools to any MCP-compatible AI CLI. - -### Auto-Start At Windows Logon - -```powershell -powershell -ExecutionPolicy Bypass -File install-autostart.ps1 -``` - -### Manual Start - -```powershell -powershell -ExecutionPolicy Bypass -File start-mcp-server.ps1 -``` - -### Claude Code - -```json -{ - "mcpServers": { - "github": { - "type": "sse", - "url": "http://localhost:8765/sse" - } - } -} -``` - -### Gemini CLI / Codex CLI - -Point MCP configuration at `http://localhost:8765/sse`. - -## Architecture Summary - -The MCP server is spawned as a stdio child process by the orchestrator, separate from -the HTTP instance used by AI CLIs. - -```text -GithubMCP/ -|-- github-mcp-server.exe -|-- start-mcp-server.ps1 -|-- install-autostart.ps1 -|-- .env.example -`-- src/GsdOrchestrator/ - |-- Program.cs - |-- Auth/ - |-- Checkpointing/ - |-- Mcp/ - `-- Workflows/ - |-- GsdStateMachine.cs - |-- Models/ - `-- States/ -``` +*For a deep dive into the internal graph architecture, please see the [Wiki](WIKI/Home.md).* diff --git a/WIKI/Architecture.md b/WIKI/Architecture.md new file mode 100644 index 0000000..73bb6d9 --- /dev/null +++ b/WIKI/Architecture.md @@ -0,0 +1,19 @@ +# Architecture + +GSD Orchestrator uses a durable state machine in C# to manage the Issue-to-PR lifecycle. + +## Pipeline Flow + +\\\mermaid +graph TD; + Issue[GitHub Issue] --> Ingestion[Context Ingestion] + Ingestion --> Planning[Architecture Planning] + Planning --> Branching[Branch Creation] + Branching --> Execution[Code Editing] + Execution --> Validation[Test Execution] + Validation --> PR[Pull Request Creation] + PR --> Merge[Auto-Merge on CI Pass] +\\\ + +## Resilience +The pipeline is wrapped in Polly retry policies, ensuring that API rate limits from GitHub or Claude never kill a long-running resolution task. diff --git a/WIKI/Home.md b/WIKI/Home.md new file mode 100644 index 0000000..9da130c --- /dev/null +++ b/WIKI/Home.md @@ -0,0 +1,6 @@ +# GSD Orchestrator Wiki + +Welcome to the internal documentation for GSD Orchestrator. + +## Table of Contents +1. [Architecture & Flow](Architecture.md) diff --git a/docs/assets/concept.png b/docs/assets/concept.png new file mode 100644 index 0000000..aad051f Binary files /dev/null and b/docs/assets/concept.png differ diff --git a/src/GsdOrchestrator/Checkpointing/FileCheckpointStore.cs b/src/GsdOrchestrator/Checkpointing/FileCheckpointStore.cs index a0ac659..ff72a83 100644 --- a/src/GsdOrchestrator/Checkpointing/FileCheckpointStore.cs +++ b/src/GsdOrchestrator/Checkpointing/FileCheckpointStore.cs @@ -26,7 +26,8 @@ public sealed class FileCheckpointStore : ICheckpointStore private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() } }; /// @@ -53,7 +54,10 @@ public async Task SaveAsync(GsdWorkflowContext ctx, CancellationToken ct = defau var tmp = path + ".tmp"; await using (var fs = new FileStream(tmp, FileMode.Create, FileAccess.Write, FileShare.None)) + { await JsonSerializer.SerializeAsync(fs, ctx, JsonOpts, ct); + fs.Flush(flushToDisk: true); + } // Atomic rename — prevents partial writes leaving corrupt checkpoints File.Move(tmp, path, overwrite: true); diff --git a/src/GsdOrchestrator/Program.cs b/src/GsdOrchestrator/Program.cs index 888b803..338469c 100644 --- a/src/GsdOrchestrator/Program.cs +++ b/src/GsdOrchestrator/Program.cs @@ -245,6 +245,10 @@ static async Task RunWatchModeAsync( interval.Repositories.Count); } catch (OperationCanceledException) when (ct.IsCancellationRequested) { break; } + catch (Exception exception) + { + logger.LogError(exception, "Unhandled exception in watch mode interval; will retry next interval"); + } try { await Task.Delay(pollInterval, ct); } catch (OperationCanceledException) { break; }