Add the AI agent path - #2
Merged
Merged
Conversation
…ions, dispatch, MCP server, and authorization +semver: minor
- Mission entities + REST + Layer-1 dispatch + Layer-2 agent endpoints (server)
- Agent process with Claude sidecar; SignalR-streamed results into ModuleJobMission/Run
- MCP server surface (Resources/Tools/Prompts) over snapcd:// URIs
- Mission authorization: AgentRoles, per-scope AgentAssignments, IsAssignedToAllModules
- Agent as a first-class audit principal alongside User and ServicePrincipal
- ILicenseInfoProvider in Server.Core abstracts the license-tier lookup; concrete LicenseService lives in Server.Host
- SnapCd.Mcp.Generator emits the MCP tool/resource surface from [ExposeAsMcpTool] / [ExposeAsMcpResource] attributes on controllers
- SnapCd.Settings.Generator.{Server,Runner,Agent} emit per-component settings JSON schemas from the strongly-typed Settings classes
- Create a more tenable Test approach for secured repos
|
All contributors have signed the CLA. ✅ |
Contributor
Author
|
I have read the CLA Document and I hereby sign the CLA |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Closes #1.
Lands the full agent feature described in the linked issue: a registered Agent entity, server-side Missions that match-and-dispatch invocations to it, an Agent process with a Claude sidecar, an MCP surface for the sidecar to use, and per-scope authorization + audit attribution end-to-end.
The three mission types are still quite simple, but the full machinery for much more complex (and useful!) ones are there in this PR.
What ships
Server — entities, REST, dispatch
Runneras closely as possible — same shape of secured repositories, controllers, DTOs, role enum, and assignment subclasses.AgentStackAssignment,AgentNamespaceAssignment,AgentModuleAssignment) +Agent.IsAssignedToAllModulesflag for the broad-allow case. Authorization is the supply/demand AND: scope owner controls Mission creation; Agent owner controls Assignment creation; dispatch enforces the conjunction.OrganizationMission,StackMission,NamespaceMission,ModuleMission. Each carries aMissionType, an optionalSidecarName, and per-scope FKs. Created through the same REST + Razor + Terraform-provider channels every other resource uses.MissionMatcher/MissionDispatcher): competing consumers triggered by saga events (ApplyModuleCompleted/Failed/Cancelled,DealWithApprovalStatusdeclined path). Walks the relevant Missions, resolves matching Agent supply viaAgentSupplyResolver, dispatches to a chosen agent.AgentEndpoints): one named endpoint + DTO + handler per mission type (AutoDiagnose,ApprovalRecommend,SummarizeJob,CancelMission). No generic invoke shim — every mission has an explicit, typed wire shape.RunnerHub. Carries dispatch, heartbeat, log streaming, run lifecycle (MissionStarted/MissionHeartbeat/AddMissionLogs/MissionCompleted/MissionFaulted/MissionCancelled).agent_idclaim issued via OpenIddict, so any REST call an Agent makes is attributable to it. Agents authenticate as Service Principals; the extra claim threads the Agent identity through.Server — MCP surface
AddSnapCdMcpServer+MapMcp("/mcp")) exposing Resources, Tools, and Prompts. License-gated to Enterprise; bearer-authenticated.SnapCd.Mcp.Generator— a source generator that emits*McpSurface.g.cs+*McpResourceSurface.g.csfiles from[ExposeAsMcpTool]and[ExposeAsMcpResource]attributes on controllers. The MCP surface is generated, not hand-maintained.prompts/listandprompts/get. The mission editor's skill picker consumes the same endpoint, so the UI is automatically in sync with the available skills.snapcd://orgs/{orgId}/{entity-plural}/{entityId}/{sub-path}; org scoping is enforced server-side from the bearer claim.Agent process + Claude sidecar
SnapCd.Agent— a long-running .NET process with aMissionsorchestrator that:CancelMissioncancels the matching sidecar invocation).SnapCd.Agent.AppHost— .NET Aspire host that wires the Agent + sidecars locally for dev.SnapCd.Agent/Sidecars/Claude/) — a FastAPI service that:prompts/getendpoint (no bundled local skill copies).logevents; emits a finalresultevent with the run outcome.Mission types
Three mission types ship in this PR. Each has a typed request DTO, a Layer-2 agent endpoint, a built-in skill that resolves via MCP
prompts/get, and a per-mission consumer that drives the invocation.AutoDiagnose — fires when a
ModuleJobends in failure or cancellation (ApplyModuleFailed,ApplyModuleCancelled,DestroyModuleFailed,DestroyModuleCancelled, plus the declined-approval path throughDealWithApprovalStatus). The agent walks the failed job's logs, the module's resolved configuration, and recent runs of related modules via MCP, then writes back a structured diagnosis: a free-text explanation plus aDiagnosisCategoryenum so the UI can colour-code and the operator can filter. Surfaced in the Module Job's Missions tab and on the Module dashboard.ApprovalRecommend — fires when a
ModuleJobreaches awaiting-approval state. The agent reads the proposed plan, the module's history, and any related changes via MCP, then writes back an approve / decline recommendation with reasoning. The recommendation is advisory — the operator still clicks the approve / decline button — but it sits next to the plan diff so it's there when the decision is being made.SummarizeJob — fires when a
ModuleJobcompletes successfully (ApplyModuleCompleted,DestroyModuleCompleted). The agent produces a brief human-readable summary of what actually changed: resources added / modified / destroyed, notable side effects, anything that looked unusual mid-run. Persisted on the run record and rendered as the headline of the Missions tab so a quick scan of a module's history reads as prose, not raw plan output.All three share the same dispatch and result-capture machinery — the differences are entirely in the skill prompt, the structured-report shape, and the trigger event. New mission types slot in by adding a
MissionTypeenum value, a request DTO + endpoint constant, a consumer, and an MCP prompt — no changes to the dispatch fabric.Mission shape, audit, UI
ModuleJobMission+ModuleJobMissionRunchild tables — durable per-attempt records for each mission invocation against aModuleJob. Idempotent under retry.CreatedByAgentId/ModifiedByAgentIdcolumns on audit-tracked tables;PrincipalDiscriminatorextended.SidecarNameso an Agent hosting multiple sidecars can be routed to the right one. Default-sidecar resolution when omitted.Other generators landing alongside
SnapCd.Settings.Generator.{Server,Runner,Agent}— per-component settings JSON-schema generators emit the schema for each component's strongly-typed Settings classes. Not strictly part of the agent path but landed together because they're touched by the same component split.