This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Note: This is the Umbraco.AI.Prompt.Deploy package. See the root CLAUDE.md for shared coding standards, build commands, and repository-wide conventions that apply to all packages.
# Build the solution
dotnet build Umbraco.AI.Prompt.Deploy.slnx
# Run tests
dotnet test Umbraco.AI.Prompt.Deploy.slnxUmbraco.AI.Prompt.Deploy provides Umbraco Deploy integration for AI prompt templates. It enables deployment of prompts with their scoping rules, profile dependencies, and configurations.
Single-project structure (consistent with Deploy pattern):
| Project | Purpose |
|---|---|
Umbraco.AI.Prompt.Deploy |
Service connector, artifact, notification handlers |
Umbraco.AI.Prompt.Deploy.Tests.Unit |
Unit tests |
Artifact - AIPromptArtifact:
- Basic properties (Alias, Name, Description, Instructions)
- Optional ProfileUdi for profile dependency
- ContextIds array (future feature)
- Tags array for categorization
- Scope as JsonElement (serialized AIPromptScope)
- Settings (IsActive, IncludeEntityContext, OptionCount)
Service Connector - UmbracoAIPromptServiceConnector:
- Extends
UmbracoAIProfileDependentEntityServiceConnectorBase - Handles prompt-to-profile dependency resolution
- Serializes/deserializes AIPromptScope to/from JSON
Notification Handlers:
AIPromptSavedDeployRefresherNotificationAsyncHandler- Writes artifacts on saveAIPromptDeletedDeployRefresherNotificationAsyncHandler- Deletes artifacts on delete
Uses UmbracoAIProfileDependentEntityServiceConnectorBase<AIPromptArtifact, AIPrompt>:
- Automatic Pass 2/4 pattern for profile resolution
AddProfileDependency(Guid?, ArtifactDependencyCollection)helperResolveProfileIdAsync(GuidUdi?, CancellationToken)helper- Reduces code duplication with Agent connector
Pass 2: Create/Update Prompt
private async Task Pass2Async(...)
{
// ProfileId can be null initially
var prompt = new AIPrompt
{
Alias = artifact.Alias,
Name = artifact.Name,
Description = artifact.Description,
Instructions = artifact.Instructions,
ProfileId = null, // Resolved in Pass 4
ContextIds = artifact.ContextIds.ToList(),
Tags = artifact.Tags.ToList(),
Scope = DeserializeScope(artifact.Scope),
IsActive = artifact.IsActive,
IncludeEntityContext = artifact.IncludeEntityContext,
OptionCount = artifact.OptionCount
};
await _promptService.SavePromptAsync(prompt, ct);
}Pass 4: Resolve Profile Dependency
private async Task Pass4Async(...)
{
// Use base class helper
var profileId = await ResolveProfileIdAsync(artifact.ProfileUdi, ct);
prompt.ProfileId = profileId;
await _promptService.SavePromptAsync(prompt, ct);
}AIPromptScope is serialized to JSON for artifact storage:
// To artifact
artifact.Scope = entity.Scope != null
? JsonSerializer.SerializeToElement(entity.Scope)
: null;
// From artifact
var scope = artifact.Scope.HasValue
? JsonSerializer.Deserialize<AIPromptScope>(artifact.Scope.Value)
: null;AIPromptScope Structure:
public class AIPromptScope
{
public List<AIPromptScopeRule> AllowRules { get; set; }
public List<AIPromptScopeRule> DenyRules { get; set; }
}
public class AIPromptScopeRule
{
public List<string> ContentTypeAliases { get; set; }
public List<string> PropertyAliases { get; set; }
public List<string> PropertyEditorAliases { get; set; }
}- .NET 10.0 (
net10.0) - Uses Central Package Management (
Directory.Packages.props) - Nullable reference types enabled
- Umbraco CMS 17.x
- Umbraco.AI 1.x
- Umbraco.AI.Prompt 1.x
- Umbraco.AI.Deploy 1.x
- Umbraco Deploy 17.x
Unit tests cover:
- Artifact creation with all properties populated
- Artifact creation with minimal/optional properties (null cases)
- Profile dependency tracking (ProfileUdi added to dependencies)
- Scope serialization/deserialization
- ContextIds preservation
- Tag arrays
public override Task<AIPromptArtifact?> GetArtifactAsync(...)
{
var dependencies = new ArtifactDependencyCollection();
// Use base class helper
var profileUdi = AddProfileDependency(entity.ProfileId, dependencies);
var artifact = new AIPromptArtifact(udi, dependencies)
{
ProfileUdi = profileUdi,
// ... other properties
};
}// Handle null scope
artifact.Scope = entity.Scope != null
? JsonSerializer.SerializeToElement(entity.Scope)
: null;
// Handle empty collections
artifact.ContextIds = entity.ContextIds.ToList(); // Empty list if none
artifact.Tags = entity.Tags.ToList(); // Empty list if none- Umbraco.AI.Deploy CLAUDE.md - Base connector patterns
- Umbraco.AI.Prompt CLAUDE.md - Prompt domain model