feat(spine): reshape Workspace → board (Projects v2) spanning many repos + multi-repo sessions#30
Open
hoangsnowy wants to merge 4 commits into
Open
feat(spine): reshape Workspace → board (Projects v2) spanning many repos + multi-repo sessions#30hoangsnowy wants to merge 4 commits into
hoangsnowy wants to merge 4 commits into
Conversation
…ny repos A Workspace was one repo; it is now a planning board (GitHub Projects v2) that spans many repos, surfaced as a unified, filterable ticket feed. - Domain: BoardDescriptor + board members on ISourceProvider + BoardTicket/ BoardSummary/BoardValidation. WorkspaceDescriptor.ForRepo insulation factory keeps per-repo services (PR creation, repo validate) signature-unchanged. - Integration: GitHubProjectsClient reads boards + items via raw GraphQL (Octokit REST has no Projects v2) projecting Issue/PR/DraftIssue + Status; BoardTicketService; ADO stays a graceful stub behind the same seam. - Workspaces: WorkspaceEntity repurposed as the board binding + a WorkspaceRepoEntity child (cascade FK). ReshapeWorkspaceToBoard migration folds each existing single-repo workspace into board + one repo row. Repo-child CRUD + a validated AddRepoAsync on the connector. - Sessions: a session captures its target repo (RepoOwner/RepoName/branch) so a ticket -> session run stays coherent; AddSessionRepoCoords migration. - Web: SpineApp "Boards" tab — connect-a-board, repos sub-list, unified tickets with repo/label/status filters; sessions show their target repo. - Tests: board connect + add-repo + GraphQL->BoardTicket mapping (346 passed). Stage 1 of the board reshape. Multi-repo execution (one session -> N repos -> N linked PRs) follows in a later PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A lightweight "web" config (dotnet run src/AgentOs.Web, no-op repos) alongside the full "aspire" stack, for fast standalone UI verification. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize a session from one repo to many: a board ticket can be worked across several services at once, each getting its own branch + PR. - Domain: IssueWorkRequest now carries a list of WorkRepo; IssueWorkResult returns a per-repo RepoWorkOutcome list. - Pipeline: IssueWorkAgent runs the agentic loop sequentially per repo (reusing the single-repo prompt + parser); IssueWorkPrompt is per-repo with a cross-service note so the PRs cross-link. - Sessions: new SessionRepoEntity child (N target repos per session, each with its own branch/PR/status); RemoteSessionEntity keeps a primary repo for display + gains BoardItemNodeId/TicketKind. AddSessionRepos migration folds existing single-repo sessions into one child row. Child CRUD + RecomputeSessionStatus (children roll up into the parent). - Web: "Work on this" opens a repo multi-select dialog (pre-selects the ticket's repo); RunSession loops repos → one PR each, writing results back incrementally; the Sessions tab shows a per-repo breakdown with a PR link. - Cleanup: removed the now-dead IGitHubIssueService/GitHubIssueService; relabeled the Settings GitHub tab as Pipeline-only (Spine uses per-board tokens); Spine app caption → "Boards → tickets → AI sessions". - Tests: multi-repo agent loop (per-repo outcomes, one-fails aggregate, empty repos). 349 passed / 0 failed. Stages 2-4 of the board reshape; completes one session -> N repos -> N PRs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dev-auth UI E2E (SpineAppTests) asserted the pre-reshape "Projects" tab + the connect-a-repository PAT placeholder; the board reshape renamed them (Projects→Boards, new board PAT hint). Point the tests at the "Boards" tab + the connect-a-board placeholder. These are gated behind RUN_AGENTOS_E2E so they were skipped locally but run in CI's dev-auth step. Verified 3/3 against the standalone Web. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A Workspace was one repo; it is now a planning board (GitHub Projects v2) that spans many repos, surfaced as a unified, filterable ticket feed — and a session can work a ticket across many repos at once, opening one linked PR per repo. "1 workspace = 1 repo" was the M2 shortcut and the root of the GitHub/ADO UX pain; this matches the roadmap's H2 "Boards" intent and how multi-service work actually looks.
GitHub-first; Azure DevOps stays a graceful stub behind
ISourceProvider(drops in later with no reshape). All work stays inside the existing modules — no new products.Stages (all in this PR)
GitHubProjectsClientreads boards + items via raw GraphQL (Octokit REST has no Projects v2); SpineApp "Boards" tab with repos sub-list + tickets filtered by repo/label/status.SessionRepoEntitychild (N target repos per session, each its own branch/PR/status); sessions show a per-repo breakdown.IssueWorkRequestcarries N repos;IssueWorkAgentruns per repo; "Work on this" → repo multi-select dialog;RunSessionopens one PR per repo (incremental write-back, per-repo try/catch);RecomputeSessionStatusrolls children up.IGitHubIssueService; relabeled Settings GitHub tab as Pipeline-only (Spine uses per-board tokens); app caption → "Boards → tickets → AI sessions".Key design
WorkspaceDescriptor.ForRepo(board,…)insulation factory → per-repo services (PR creation, repo validate) keep their signatures. Low blast radius.ReshapeWorkspaceToBoard(each existing workspace → board + one repo) andAddSessionRepos(each existing session → one child repo). No data loss.runner_shellalready takesworking_dir, so N repos = N working dirs, no protocol change.Test plan
dotnet test AgentOs.slnx -c Release→ 349 passed / 5 skipped (live-LLM) / 0 failed, 0 warnings (TreatWarningsAsErrors).BoardTicketmapping (Issue/PR/DraftIssue, null-repo drafts, Status), multi-repo agent loop (per-repo outcomes, one-fails aggregate, empty repos),BoardTicketService.repo+read:project) + a real Projects v2 board — needed to verify the live GraphQL ticket fetch, persistence, the migration folds, and an end-to-end multi-repo run (needs a paired runner). (Maintainer creds required.)Maintainer verification (real-service path)
dotnet run --project infra/AgentOs.AppHost→ Web https://localhost:5180, loginoperator/operator.repo+read:project.🤖 Generated with Claude Code