Create or modify a CoreEx Application-layer policy class. USE FOR: new policy class in Application/Policies/, EnsureExists guard (referenced entity must exist), business rule guards requiring I/O, multi-method policy, composing policies in Result<T> pipelines. DO NOT USE FOR: synchronous validation rules (use coreex-validator), Infrastructure repositories (use coreex-repository), application service scaffolding (use coreex-app-service).
Scanned 8/31/2026
Install to Claude Code
npx -y skills add Avanade/CoreEx --skill coreex-policy --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Coreex Policy?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/avanade-coreex-policy)More formats (shields.io, HTML) on the badges page.
---
name: coreex-policy
description: "Create or modify a CoreEx Application-layer policy class. USE FOR: new policy class in Application/Policies/, EnsureExists guard (referenced entity must exist), business rule guards requiring I/O, multi-method policy, composing policies in Result<T> pipelines. DO NOT USE FOR: synchronous validation rules (use coreex-validator), Infrastructure repositories (use coreex-repository), application service scaffolding (use coreex-app-service)."
argument-hint: "Optional: entity being guarded, type of guard (exists-check / business-rule / state-check), adapter or repository the policy calls"
tags: ["policy", "application-layer", "result", "guard", "adapter", "anti-corruption", "coreex"]
---
<!--
AI workflow asset — dual-audience notice:
- In the Avanade/CoreEx repository: this file is the authored source. Edit it here.
- In a consumer repository: this file was generated by `dotnet new coreex-ai` (or refreshed via
`dotnet new coreex-ai --force` / the `/coreex-docs-sync` skill). Do not hand-edit it directly —
propose the change upstream in Avanade/CoreEx instead, then refresh once it is released.
-->
# CoreEx: Policy
Guides you through creating or modifying a CoreEx Application-layer policy class in `Application/Policies/`. Policies encapsulate **domain-level guard logic that requires async I/O** — adapter or repository calls — providing a named, independently testable home for rules that cannot live in a synchronous validator or directly in the domain model.
## When to Use
- A guard check needs to call an adapter (external domain) or a repository — synchronous validators cannot do this
- An "ensure referenced entity exists" check that must translate `NotFoundError` into a user-visible validation error
- A business-rule check (e.g. entity is inactive, quota exceeded) that requires loading state
- Multiple related guards that share the same adapter/repository dependency — group them in one policy class
## When Not to Use
- Synchronous field validation (no I/O) — use the `coreex-validator` skill
- Guard logic that belongs entirely inside the domain aggregate — keep it in the aggregate method
- Service scaffolding — use the `coreex-app-service` skill; it covers how to wire a policy into a service
## Quick Reference
**Clarifying questions before writing any code:**
0. Resolve `rop-enabled` (`Result<T>` vs exception style — policies compose into `Result<T>` pipelines) from the solution-root `AGENTS.md` **Feature Configuration** before asking the rest; only prompt for what is unrecorded and re-state resolved values for confirmation.
1. What entity / concept is being guarded? (names the policy class)
2. What type of guard? EnsureExists / business rule / state check
3. Which adapter or repository does the policy call?
4. Should the policy return the loaded entity (`Result<T>`) or just a pass/fail (`Result`)?
5. Multiple guard methods in one class, or one method only?
**Key rules at a glance:**
- Policy lives in `Application/Policies/{Name}Policy.cs`
- **Not DI-registered** — instantiated at the call site: `new {Name}Policy(_adapter).EnsureExistsAsync(id)`
- Constructor accepts adapters and/or repositories already injected into the calling service
- Always returns `Result` or `Result<T>` — never throws (unless adapter itself throws unexpectedly)
- **EnsureExists:** translate `r.IsNotFoundError` → `Result.ValidationError(...)` — do not let `NotFoundException` propagate as-is
- `MessageItem.CreateErrorMessage(nameof(param), "{Entity} was not found.")` produces a field-level validation error
- `LText` static fields hold **localizable entity names** used inside message text — e.g. `new LText("Product")` as the `{0}` substitution in `"{0} was not found."`. The **property name** (`nameof(param)`) is always a plain `string?` — never `LText`
- Guard methods can return the loaded entity as `Result<Contracts.T>` so callers can use it without a second fetch
- Always `.ConfigureAwait(false)` on every `await`
- **Always generate a matching `{Name}PolicyTests.cs`** in `*.Test.Unit/Policies/` — cover the success path (expect `IsSuccess`) for each guard method, plus its failure path: `IsValidationError` for `EnsureExists`-style not-found guards, `IsBusinessError` for state/condition guards (e.g. `EnsureActive`)
For full workflow and code examples see [`references/workflow.md`](references/workflow.md).
## Key References
- [`/.github/instructions/coreex-application-services.instructions.md`](/.github/instructions/coreex-application-services.instructions.md) — policies, adapters, DI registration principle, Result<T> pipeline operators
- Related skills: [`coreex-app-service`](../coreex-app-service/SKILL.md) (wires the policy into a service), [`coreex-adapter`](../coreex-adapter/SKILL.md) + [`coreex-repository`](../coreex-repository/SKILL.md) (the dependencies a policy calls), [`coreex-validator`](../coreex-validator/SKILL.md) (synchronous, no-I/O guard sibling)
- Illustrative examples (CoreEx sample — not present in your project):
- [`ProductPolicy`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Shopping.Application/Policies) — EnsureExists translating NotFoundError → ValidationError
- [`BasketService.cs`](https://github.com/Avanade/CoreEx/blob/main/samples/src/Contoso.Shopping.Application/BasketService.cs) — `ItemAddAsync` shows a policy in a `Result.GoAsync().ThenAsAsync()` pipeline
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!