AgentRegistryService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-04 Asset Publication |
| Platform / plane | Control Plane / Control |
| Deployment granularity | module of host · host ControlPlaneApi |
| Status | target · ConnectSoft.Factory.Publication |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-saas-abstractions, connectsoft-extensions-saas-asp-net-core, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-data-storage-abstractions |
| Decisions | ADR-0002, ADR-0021, ADR-0022, ADR-0023 |
| Traceability | FR-02 FR-11 FUX-02 FUX-10 NFR-02 NFR-11 NFR-13 XL-02 XL-08 XL-15 |
Purpose and responsibilities¶
Every asset the Factory executes is a Git-authored artifact that becomes usable only as a published, immutable release. AgentRegistryService turns a source commit into a release candidate, resolves its complete dependency closure (an agent's skills, their tools and MCP servers, the workflow's agents, the policy bundle, the model profile), hashes the manifest, records the evaluation verdict and the reviewer approval, and publishes. It then serves two readers: Run Control resolves an alias or release id at submission, and the runtime loads a release's content references at attempt start.
The service is the registry for all asset kinds (agents, skills, tools, workflows, policies, model profiles, editions, template bundles). It absorbs the June-2026 rows SkillRegistryService and WorkflowDefinitionService (same registry module, different asset kinds) and the publication half of the Agent Mesh registry rows; the runtime keeps only a read model of Published releases. Agent card projection for A2A discovery is split into AgentCardService so that discovery can evolve with the protocol without touching publication.
Git remains the authoring authority (D19: the Factory asset source is new, not AgentKit); the Studio never edits assets in place.
Context and boundaries¶
flowchart LR
S["AgentRegistryService"]
RunControlService["RunControlService"] -->|grpc| S
AgentRuntimeService["AgentRuntimeService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|sync-http| ext_azure_devops["ext-azure-devops"]
S -->|event| QualityScoreService["QualityScoreService"]
S -->|grpc| RunControlService["RunControlService"]
S -->|grpc| ArtifactService["ArtifactService"]
S -. "AssetReleaseSubmitted" .-> E_AssetReleaseSubmitted(("event"))
S -. "AssetReleasePublished" .-> E_AssetReleasePublished(("event"))
S -. "AssetReleaseDeprecated" .-> E_AssetReleaseDeprecated(("event"))
S -. "AssetReleaseRevoked" .-> E_AssetReleaseRevoked(("event"))
Lifecycle and gates:
Draft → InReviewon submission from a commit (Asset maintainer).InReview → Publishedonly when the closure is complete and compatible, the evaluation record passes the profile's thresholds (quality gates, D32) or a recorded waiver exists, and a Reviewer who is not the author approves through a Run Control approval request of classpublication(D21, D18).Published → Deprecatedwith an in-flight policy (finish, drain or revoke); accepted runs keep their pinned release.- Revocation is a security or policy action that withdraws cards and tells Run Control and the runtime what to do with in-flight runs.
Domain model¶
AssetRelease — One immutable release of one asset with its complete dependency closure, source commit, hashes, evaluation verdict and approval. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
releaseId |
string |
yes | |
tenantId |
string |
yes | Tenant that owns the asset; ConnectSoft-published assets use the platform tenant. |
assetKind |
enum:AssetKind |
yes | |
assetId |
string |
yes | |
version |
string |
yes | |
state |
enum:ReleaseState |
yes | |
sourceRepository |
string |
yes | |
sourceCommit |
string |
yes | |
manifestHash |
hash |
yes | Hash over the release manifest (release-manifest-v1). |
evaluationRecordRef |
string |
no | Artifact reference of the evaluation record (ADR-0021). |
approvalId |
guid |
no | |
publishedAt |
datetime |
no | |
publishedBy |
string |
no | |
version_ |
long |
yes | Optimistic concurrency token. |
Invariants:
- Publication is blocked while any closure entry is missing, not Published, or incompatible with the declared runtime adapter.
- The same inputs produce the same manifestHash; a changed dependency changes the release id.
- A Published release is immutable; changes produce a new version. Deprecation keeps the manifest readable.
- A release reaches Published only with an evaluation verdict of passed (or a recorded waiver) and a Reviewer approval that is not the author (ADR-0021, D18).
stateDiagram-v2
Draft --> InReview : SubmitForReview
InReview --> Published : GatesPassedAndApproved
InReview --> Draft : RejectedOrChanged
Published --> Deprecated : Deprecate
Events: AssetReleaseSubmitted, AssetReleasePublished, AssetReleaseDeprecated, AssetReleaseRevoked · Tables: AssetReleases, ReleaseClosure, ReleaseAliases · Repository: AssetReleaseRepository
erDiagram
AssetRelease {
string releaseId PK
string tenantId
enum_AssetKind assetKind
string assetId
string version
enum_ReleaseState state
string sourceRepository
string sourceCommit
hash manifestHash
string evaluationRecordRef
guid approvalId
datetime publishedAt
string publishedBy
long version_
}
ClosureEntry {
enum_AssetKind kind
string assetId
string version
hash hash
}
Alias {
string name
string releaseId
datetime movedAt
string movedBy
}
Signature {
string algorithm
string keyId
string value
}
AssetRelease ||--o{ ClosureEntry : contains
AssetRelease ||--o{ Alias : contains
stateDiagram-v2
[*] --> Draft
Draft --> InReview: SubmitForReview
InReview --> Published: GatesPassedAndApproved
InReview --> Draft: RejectedOrChanged
Published --> Deprecated: Deprecate
Deprecated --> [*]
Release ids are content-addressed: <kind>/<assetId>@<version>+<hash8>. Two submissions with the same inputs produce the same manifest hash; a dependency that moved produces a different id even if the asset's own files did not change. Aliases (latest, stable) are mutable pointers that select a release at submission time only (Control plane invariant).
Entities and value objects¶
ClosureEntry (entity, in AssetRelease) — One resolved dependency with exact version and hash.
| Field | Type | Required | Description |
|---|---|---|---|
kind |
enum:AssetKind |
yes | |
assetId |
string |
yes | |
version |
string |
yes | |
hash |
hash |
yes |
Alias (entity, in AssetRelease) — A mutable name (latest, stable) pointing at a release; moving an alias never changes accepted runs.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
yes | |
releaseId |
string |
yes | |
movedAt |
datetime |
yes | |
movedBy |
string |
yes |
Signature (value-object) — Detached signature over the manifest hash.
| Field | Type | Required | Description |
|---|---|---|---|
algorithm |
string |
yes | |
keyId |
string |
yes | |
value |
string |
yes |
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Control plane relational store | primary | azure-sql / nhibernate-sqlserver | AssetReleases, ReleaseClosure, ReleaseAliases |
| Artifact content store | blob | blob / azure-blob | — |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.AssetReleases |
AssetRelease | 15 | 2 |
dbo.ReleaseClosure |
ClosureEntry | 6 | 0 |
dbo.ReleaseAliases |
Alias | 7 | 0 |
Full DDL: appendix.
Rows live in the publication schema of control-sql; manifests, closure content references and evaluation records are blobs in artifact-blob referenced by hash, so the database stays small and the manifest is verifiable from the blob alone. Platform-published assets belong to the platform tenant and are visible to every tenant; tenant-published assets are tenant-scoped.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
POST |
/factory/asset-releases/validate |
ValidateRelease | factory.assets.write |
sandbox | natural | GW-03 | Resolve the closure of a candidate from Git and report missing, unreviewed or incompatible dependencies without publishing. |
POST |
/factory/asset-releases |
SubmitRelease | factory.assets.write |
publication | key-header | GW-03 | Create an InReview release candidate from a source commit; triggers evaluation. |
POST |
/factory/asset-releases/{releaseId}/publish |
PublishRelease | factory.assets.publish |
publication | natural | GW-03 | Move an InReview candidate to Published after gates and approval (approval-gated action). |
POST |
/factory/asset-releases/{releaseId}/deprecate |
DeprecateRelease | factory.assets.publish |
publication | natural | GW-03 | Deprecate a Published release with an in-flight policy. |
GET |
/factory/asset-releases/{releaseId} |
GetRelease | factory.assets.read |
read | natural | GW-03 | Manifest, closure, evidence and aliases. |
GET |
/factory/asset-releases |
ListReleases | factory.assets.read |
read | natural | GW-03 | Releases filtered by kind, asset, state. |
PUT |
/factory/assets/{assetKind}/{assetId}/aliases/{name} |
MoveAlias | factory.assets.publish |
publication | natural | GW-03 | Point an alias at a Published release; accepted runs are unaffected. |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
AssetPublication |
ResolveRelease |
none | internal | read | Resolve an alias or release id to an immutable release with its closure; used by Run Control at submission. |
AssetPublication |
LoadRelease |
server | internal | read | Stream the manifest and closure content references for release loading in the runtime (BC-06). |
Example manifest (release-manifest-v1, see shared contracts):
{
"releaseId": "agent/repository-assessor@1.4.0+9f3c2a1b",
"assetKind": "Agent",
"sourceRepository": "ConnectSoft.Factory.Assets",
"sourceCommit": "a1b2c3d4e5f6",
"closure": [
{ "kind": "Skill", "assetId": "repo-scan", "version": "2.1.0", "hash": "sha256:..." },
{ "kind": "Tool", "assetId": "git-read", "version": "1.0.3", "hash": "sha256:..." },
{ "kind": "ModelProfile", "assetId": "code-agent", "version": "3", "hash": "sha256:..." }
],
"evaluationRecordRef": "artifact://evaluations/agent/repository-assessor@1.4.0/record.json",
"manifestHash": "sha256:..."
}
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| AssetReleaseSubmitted | asset-publication.releases.v1.asset-release-submitted |
integration / 1 | AssetRelease | QualityScoreService, StudioBff | A release candidate entered InReview; evaluation must run. |
| AssetReleasePublished | asset-publication.releases.v1.asset-release-published |
integration / 1 | AssetRelease | TemplateRegistryService, BlueprintService, FleetRolloutService, PolicyEngineService, McpServerRegistryService, ToolAdapterService, ModelRouterService, WorkflowEngineService, AgentRuntimeService, AgentCardService, StudioBff, AuditService, MarketplaceCatalogService | A release is Published and loadable. |
| AssetReleaseDeprecated | asset-publication.releases.v1.asset-release-deprecated |
integration / 1 | AssetRelease | TemplateRegistryService, BlueprintService, MarketplaceCatalogService, ToolAdapterService, ModelRouterService, AgentRuntimeService, RunControlService, AgentCardService, StudioBff | No new runs may pin this release. |
| AssetReleaseRevoked | asset-publication.releases.v1.asset-release-revoked |
integration / 1 | AssetRelease | MarketplaceCatalogService, PolicyEngineService, McpServerRegistryService, ToolAdapterService, ModelRouterService, AgentRuntimeService, RunControlService, AgentCardService, AuditService | A release was revoked for a security or policy reason; in-flight runs follow the stated policy. |
AssetReleaseSubmitted payload:
| Field | Type | Required | Description |
|---|---|---|---|
releaseId |
string |
yes | |
tenantId |
string |
yes | |
assetKind |
enum:AssetKind |
yes | |
assetId |
string |
yes | |
version |
string |
yes | |
manifestHash |
hash |
yes |
AssetReleasePublished payload:
| Field | Type | Required | Description |
|---|---|---|---|
releaseId |
string |
yes | |
tenantId |
string |
yes | |
assetKind |
enum:AssetKind |
yes | |
assetId |
string |
yes | |
version |
string |
yes | |
manifestHash |
hash |
yes |
AssetReleaseDeprecated payload:
| Field | Type | Required | Description |
|---|---|---|---|
releaseId |
string |
yes | |
tenantId |
string |
yes | |
inFlightPolicy |
string |
yes |
AssetReleaseRevoked payload:
| Field | Type | Required | Description |
|---|---|---|---|
releaseId |
string |
yes | |
tenantId |
string |
yes | |
reason |
string |
yes | |
inFlightPolicy |
string |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
SubmitRelease |
AssetRelease | AssetReleaseSubmitted | |
PublishRelease |
AssetRelease | AssetReleasePublished | |
DeprecateRelease |
AssetRelease | AssetReleaseDeprecated |
| Event | Producer | Handler | Purpose |
|---|---|---|---|
| ApprovalDecided | RunControlService | PublishOnApproval |
Complete publication when the publication approval is granted. |
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| ClosureResolver | event | — | exponential | releaseId + sourceCommit |
Resolves a candidate's dependency closure from Git and the registry, computes hashes and stores the manifest. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
sequenceDiagram
participant M as Asset maintainer
participant AR as AgentRegistryService
participant Q as QualityScoreService
participant RC as RunControlService
participant R as Reviewer
participant RT as AgentRuntimeService
M->>AR: POST /factory/asset-releases from commit
AR->>AR: candidate InReview, commit with outbox
AR-)Q: AssetReleaseSubmitted
AR->>AR: ClosureResolver stores manifest and hashes
Q->>AR: evaluation record passed
AR->>RC: RequestApproval class publication bound to manifestHash
R->>RC: decision approve with version
RC-)AR: ApprovalDecided
AR->>AR: Published, commit with outbox
AR-)RT: AssetReleasePublished
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Publication:Gates |
RequireEvaluation |
bool | true |
no | no | Block Published without a passed evaluation record (ADR-0021). |
Publication:Signing |
KeyId |
string | `` | no | yes | Key Vault key used to sign manifests. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.releases.published |
counter | {release} | tenant, assetKind | Releases published. |
connectsoft.factory.releases.blocked |
counter | {release} | tenant, reason | Publications blocked by closure or gate failures. |
Security¶
| Authentication | oauth2-jwt |
| Scopes | factory.assets.read (Read releases.); factory.assets.write (Submit and validate candidates (Asset maintainer).); factory.assets.publish (Publish, deprecate, move aliases (Reviewer approval required).) |
| Roles | AssetMaintainer, Reviewer, PlatformAdmin, Observer |
| Tenant isolation | row-filter |
| Data classification | internal |
| Max side-effect class | publication |
| Secrets | manifest-signing-key (key-vault, rotate 365 d) |
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ext-azure-devops | sync-http | Read asset sources at a commit. | fail-fast | yes |
| QualityScoreService | event | Evaluation runs and records for candidates. | queue | yes |
| RunControlService | grpc | Request the publication approval (D21). | fail-fast | yes |
| ArtifactService | grpc | Store manifests and evaluation records. | fail-fast | yes |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| RunControlService | grpc | ResolveRelease at submission. | — | yes |
| AgentRuntimeService | grpc | LoadRelease at attempt start. | — | yes |
| StudioBff | sync-http | Asset views and publication actions. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Source commit unreachable during closure resolution | resolver retries exhausted | candidate stays InReview with a blocking finding; maintainer resubmits | none | 30 |
| Alias moved concurrently | version conflict | second move rejected with 409 | none | 0 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host ControlPlaneApi |
| Topologies | saas-default, hybrid, on-prem |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
Nothing exists. The earlier AgentKit registry (.ai catalog, agentkit validate) is a reference input only (D19); ConnectSoft.Extensions.AI has no release or manifest concept.
Later capabilities¶
Signed manifests verified by the runtime before loading; cross-tenant asset sharing through the Marketplace (PF-07) with licence terms; software bill of materials export per release; automatic deprecation proposals when a dependency is revoked.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-02, FR-11 |
| FUX | FUX-02, FUX-10 |
| NFR | NFR-02, NFR-11, NFR-13 |
| XL | XL-02, XL-08, XL-15 |