---
name: drasi
description: >-
  USE FOR: Drasi continuous-query solutions - real-time queries, change detection,
  reactive events, data-trigger pipelines on Drasi Server, Drasi for Kubernetes, or
  drasi-lib. Router: load bundle guides as needed. DO NOT USE for non-Drasi messaging
  (event-driven-messaging) or pure AKS/ACA hosting (aks-cluster-architecture,
  azure-container-apps).
metadata:
  last_verified: "2026-08-25"
---

# Drasi Skill

Use this skill for Drasi work across hosting, embedded Rust, resource authoring, operations, security, validation, scaling, developer experience, and recovery.

Assume new projects unless the repository explicitly says otherwise. Prefer current Drasi patterns, version pinning, secure defaults, and clean replacement over legacy compatibility.

**New to Drasi?** Jump to `## 90-minute starter path` below for a runtime-specific path to a first working pipeline before reading the production-oriented `## Non-negotiable rules` and `## Day-0 workflow for new projects` sections.

## Local install ground truth (verified 2026-08-23; re-verified 2026-08-24, unchanged)

- Drasi CLI installed on this machine reports only `Drasi CLI version: latest`, the unpinned channel. This machine therefore hits the floating-tag trap documented under Non-negotiable rules unless compensated: always pass an explicit `--version 0.10.0` (or pinned release) to `drasi init` from here, never rely on the default image tag resolution.
- Version check is the subcommand `drasi version`; `drasi --version` errors with `unknown flag`.
- Installed command surface (verified via `drasi --help`): apply, completion, delete, describe, env, ingress, init, list, namespace, secret, tunnel, uninstall, version, wait, watch.

## Use When

| Should trigger | Should NOT trigger | Nearby skill collision |
| --- | --- | --- |
| Designing or reviewing Drasi Server, Drasi for Kubernetes, or `drasi-lib` continuous-query solutions | The task is generic event-driven messaging with no Drasi runtime in scope | `event-driven-messaging` for non-Drasi pub/sub architecture. **Note:** a Drasi deployment that uses Event Hubs as a Source or Event Grid/SignalR as a Reaction requires BOTH skills loaded simultaneously — see "Mandatory co-skills by deployment target". |
| Choosing providers, reactions, MCP exposure, recovery, or Azure hosting patterns for Drasi | The work is pure AKS or Container Apps hosting with no Drasi pipeline design | `aks-cluster-architecture` or `azure-container-apps` for hosting-only decisions. **Note:** Drasi for Kubernetes on AKS requires BOTH the Drasi skill and the AKS/identity skills loaded simultaneously — they are co-requisites, not alternatives. |
| Producing runtime-specific Drasi resources, validation evidence, or developer bootstrap guidance | The request is only Fabric RTI design without Drasi as the trigger layer | `microsoft-fabric` or RTI guidance when Drasi is not part of the solution |

## Current verification snapshot

Checked: 2026-08-16 (live re-verification; all pinned versions unchanged).

- Drasi is a CNCF Sandbox project.
- Drasi for Kubernetes current release line is pre-1.0. The latest public `drasi-platform` release checked here remains `0.10.0`, tagged Pre-release (unchanged since the prior 2026-06-25 check).
- Drasi Server is published as a container image at `ghcr.io/drasi-project/drasi-server`, and GitHub Releases are published for `drasi-project/drasi-server`. As of this check `v0.2.2` (published 2026-08-21) is the latest **stable** release and the rolling Latest entry points at it; a **preview** tag exists version-wise ahead of it (`0.2.3-preview`) but was cut 2026-07-13 (before the stable, and not refreshed since (prior chain `v0.2.1` → `0.2.2-preview` → `0.2.2`) - use the stable tag itself, not the rolling entry or a `-preview` tag. Note the authoritative `drasi-context.yaml` (0.7.0) still lists `0.1.6` as the "latest GitHub release" and describes `0.2.x` as in development; the context file lags the GitHub release page here, so prefer the release page for the current stable tag. Do not use the floating `latest` tag in production. Production must resolve to an immutable `@sha256:` digest before pinning, and release notes should be checked for stability signals before promotion (do not pin a `-preview` tag for production).
- Drasi Server exposes REST endpoints for sources, queries, reactions, health, OpenAPI, and interactive docs.
- Official Drasi docs publish an AI context page and `drasi-context.yaml`; use it as a currency anchor for AI-generated Drasi code, docs, and support answers. The current checked context is version `0.7.0` (updated `2026-06-16`).
- `drasi-lib` is documented as the embedded Rust option for in-process change detection. Pinning remains a deliberate decision: the official Drasi AI context currently lists `drasi-lib 0.8.6`; crates.io may move ahead of that baseline; and drasi-core continues shipping Replayable Sources / Resumable Reactions changes that can alter trait surfaces. Treat this as an explicit pinning decision, not an auto-upgrade path; see `bundles/drasi-lib/guide.md` and re-check official docs, release notes, crates.io, and docs.rs before implementation.
- **Org structure: Rust development has consolidated in `drasi-project/drasi-core`** (verified 2026-08-24), a separate monorepo from `drasi-platform`, releasing per-crate: engine plus modular plugins (`drasi-state-store-redb`, `drasi-index-garnet`/`rocksdb`, secret stores `keyring`/`file`/`azure-keyvault`, `drasi-identity-aws`, storedproc reactions, etc.). Breaking changes land there continuously without platform release notes; before pinning drasi-lib or any plugin crate for embedded work, check `drasi-core` merged PRs newer than your pin (Aug-2026 examples: RocksDB memory-budget changes, FFI push-based bootstrap receivers, `drasi_` prefix plugin scan). `drasi-server` releases track these crates; its release notes are the practical digest of what crossed into a stable line.
- PostgreSQL and Kubernetes Sources currently document delete/recreate modification behavior. SQL Server Source documents re-applying the same source name to modify, and the EventHub Source also documents re-applying the same name to modify (verified 2026-08-16).
- Microsoft Entra Workload ID is supported by PostgreSQL Source, Azure Event Hub Source, SQL Server Source, Dataverse Source, Event Grid Reaction, and SignalR Reaction (verified 2026-05-20 against Drasi for Kubernetes 0.10.0). Use `identity.kind: MicrosoftEntraWorkloadID` with `clientId` set to the user-assigned managed identity client ID. Do not assume all providers support identity - verify against current docs for any provider not in this list. **CRITICAL CORRECTION (verified against Drasi for Kubernetes 0.10.0):** For Drasi for Kubernetes on AKS, source and reaction pods do NOT use the `default` service account. Drasi creates a per-source service account named `source.<source-name>` (e.g. `source.my-source`). The federated credential subject is `system:serviceaccount:<drasi-namespace>:source.<source-name>`, NOT `system:serviceaccount:<drasi-namespace>:default`. The `identity` field is a top-level `spec` field (not inside `spec.properties`), verified against the Drasi 0.10.0 openapi `ServiceIdentityDto`. Also, the Azure Event Hub Source uses Cypher node labels as Event Hub entity names, the hub name MUST match the label used in `MATCH (m:Label)`. The `bootstrapWindow` field is an integer number of **minutes** of backfill (verified 2026-08-16 against the EventHub source docs), not seconds and not an ISO 8601 duration string; `bootstrapWindow: 300` means 5 hours, not 5 minutes.
- **Federated credential creation is a two-phase operation (verified against Drasi for Kubernetes 0.10.0).** `drasi apply -f source.yaml` creates the per-source service account, but the federated credential for that SA must be created AFTER the source is applied (Drasi creates the SA at apply time). The workflow is: (1) `drasi apply -f source-cosmos.yaml`, (2) `kubectl annotate sa source.<name> azure.workload.identity/client-id=<client-id>`, (3) `kubectl label sa source.<name> azure.workload.identity/use=true`, (4) create the federated credential in Azure: `az identity federated-credential create --subject system:serviceaccount:<ns>:source.<name>`. Without the FIC, source pods fail with `AADSTS700213: No matching federated identity record found for presented assertion subject`. The same pattern applies to reactions: the PostDaprPubSub reaction uses the `default` SA in the Drasi namespace, so a FIC must be created for `system:serviceaccount:<drasi-namespace>:default`.
- **Provider registration is not automatic on `drasi init` (verified against Drasi for Kubernetes 0.10.0).** `drasi init --version 0.10.0` deploys infrastructure and control plane but does NOT register source or reaction providers. After init, `drasi list sourceprovider` and `drasi list reactionprovider` return empty. Applying a Source with `kind: EventHub` fails with `400 Bad Request: Schema not initialized for kind: EventHub`. The fix: apply the default provider definitions from the CLI installer resources: `drasi apply -f <drasi-platform-repo>/cli/installers/resources/default-source-providers.yaml` and `drasi apply -f <drasi-platform-repo>/cli/installers/resources/default-reaction-providers.yaml`. These register EventHub, PostgreSQL, MySQL, SQLServer, CosmosGremlin, Dataverse, Kubernetes source providers and Debug, Debezium, EventGrid, EventBridge, Gremlin, Result, SignalR, StorageQueue, StoredProc, Dataverse, SyncDaprStateStore, PostDaprPubSub, Http, MCP, SyncVectorStore reaction providers.
- **CLI built from `main` defaults to `latest` tag (verified 2026-06-27).** `drasi init` without `--version` installs images tagged `latest` from `ghcr.io/project-drasi/`. These images are private (403 Forbidden on pull). Always specify `--version 0.10.0` (or the pinned release) to pull from the public `ghcr.io/drasi-project/` registry. If query container pods show `ImagePullBackOff` with `403 Forbidden` from GHCR, check the image registry path: `project-drasi` is private, `drasi-project` is public.
- Drasi MCP Reaction pins MCP spec `2025-03-26` (confirmed unchanged in Drasi docs 2026-08-16); MCP upstream is now at `2026-07-28` (Latest Stable, which introduced an extensions architecture: Tasks, MCP Apps, Skills over MCP). Drasi is three MCP spec revisions behind upstream - re-check before client implementation. See `bundles/agent-integration/guide.md`.
- **Per-component image availability varies across release lines (verified 2026-06-23; re-verified against the live GHCR tag list 2026-08-16 and re-checked 2026-08-26).** Not every component image is published for every `drasi-platform` tag, and gaps close silently between checks: the `reaction-post-dapr-pubsub` tag stopped at `0.9.2` when verified 2026-08-16 but `0.10.0` had been published by 2026-08-26 (manifest resolves; token-authenticated check). At `0.10.0`: `reaction-http`, `reaction-signalr`, `source-eventhub-proxy`, `source-eventhub-reactivator`, and `reaction-post-dapr-pubsub` all exist. At `0.9.2`: the same reaction/source images exist; `query-host` and `view-svc` were NOT found under those names (different architecture in that line, see below). Before pinning a platform release, verify every component image you plan to use exists at that tag - treat any recorded gap as stale until re-probed against the live registry.
- **Cross-minor architecture changes (verified 2026-06-23).** Drasi for Kubernetes has breaking internal architecture changes across minor versions. 0.9.x uses MongoDB + Redis state stores with components `kubernetes-provider` / `api` / `query-container`. 0.10.x uses Redis-only with components `control-plane` / `query-host` / `view-svc` / `resource-provider`. A cross-minor downgrade (e.g. 0.10.0 → 0.9.2) is a full migration, it wipes all sources/queries/reactions/state and requires recreating them against a different control-plane API. See `bundles/recovery/guide.md` `## Cross-version downgrade is not a simple reinstall`.

Always re-check the official docs and release notes before writing version-sensitive YAML, CLI commands, API calls, identity configuration, or recovery instructions.

## Capability and Runtime Verification Gate

Run this gate before recommending Drasi resources, runtime APIs, `drasi-lib` code, Azure hosting, MCP exposure, or Fabric Real-Time Intelligence integration.

1. **Choose the runtime first.** Classify the target as Drasi Server, Drasi for Kubernetes, `drasi-lib`, or mixed-runtime. Do not write YAML, REST payloads, or Rust code until the runtime is explicit.
2. **Load the currency bundle.** Read `bundles/currency-and-ai-context/guide.md` before version-sensitive work. Reconcile the official Drasi AI context, `drasi-platform` release notes, GHCR image digest, crates.io/docs.rs, and any live runtime OpenAPI or CLI output.
3. **Verify provider capability.** Check the selected Source and Reaction provider for identity support, lifecycle behavior, result contract, operation metadata, delete/update semantics, and recovery constraints. Do not generalize provider behavior across PostgreSQL, SQL Server, Kubernetes, Dataverse, Event Grid, SignalR, or MCP. **Verify the image exists:** `drasi list reactionprovider` / `drasi list sourceprovider` returns the bundled definitions but does NOT confirm the container image is published for the platform version. Before committing to a provider, confirm the image tag resolves on the registry. For GHCR public repos:
   ```powershell
   $accept = "application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.index.v1+json, application/vnd.oci.image.manifest.v1+json"
   $t = (Invoke-RestMethod -Uri "https://ghcr.io/token?scope=repository:drasi-project/<image-name>:pull&service=ghcr.io").token
   Invoke-WebRequest -Uri "https://ghcr.io/v2/drasi-project/<image-name>/manifests/<version-tag>" -Headers @{Authorization="Bearer $t"; Accept=$accept} -UseBasicParsing
   ```
   Use the manifest-list media types. GHCR returns 404 for multi-arch images when queried with only `application/vnd.docker.distribution.manifest.v2+json`. If the tag is missing, either fall back to a platform release line where the tag exists (verify ALL components are published at that line, not just the one you need), or pick a different provider/reaction.
4. **Confirm Azure or Fabric adjacency.** For Azure hosting, route to `azure-hosting` plus `azd-deployment` and `azure-deployment-preflight`. For Fabric RTI replacement or integration, route to the Fabric `real-time-intelligence` bundle and verify Eventstream/Eventhouse/KQL capability before positioning Drasi as the trigger layer.
5. **Check MCP spec alignment.** If Drasi MCP Reaction or any agent-facing endpoint is involved, record the Drasi-pinned MCP spec revision and the client/server MCP revision. Mixed revisions require an explicit compatibility decision.
6. **Capture evidence before success.** Record runtime form, version pins, docs checked, live validation commands, and source/query/reaction evidence. If any identifier cannot be verified, return an illustrative skeleton with `[VERIFY]` markers rather than production-shaped manifests.

## Multi-Region Drasi Coordination

For high-scale deployments spanning multiple regions, deploy **independent Drasi instances per region**, not shared instances. This avoids latency amplification and state synchronization gotchas.

### Architecture pattern

- **One Drasi platform per region** (e.g., `drasi-east`, `drasi-west`, `drasi-australia`)
- **Each region watches its local Cosmos replica** — sources are scoped to a single region's Cosmos read/change feed
- **Queries CAN aggregate across regions** if you wire a cross-region query coordinator (separate service)
- **Reactions run region-local; global fan-out goes through a downstream orchestrator** — when reaction output must reach subscribers in other regions, the reaction posts to a regional orchestrator service which fans out cross-region and deduplicates on an idempotency key (see "Multi-region reaction patterns" below). Do not configure Drasi reactions themselves to span regions.

### Per-region source isolation

Drasi's control-plane components (`control-plane` / `query-host` / `view-svc` / `resource-provider` at 0.10.x; `kubernetes-provider` / `api` / `query-container` at 0.9.x) are **region-local**. Event Hub and Cosmos sources watch **only the local replica**:

```yaml
# drasi-east: Event Hub source scoped to the East region Event Hubs namespace.
# Canonical Drasi for Kubernetes shape: apiVersion v1, top-level name, spec.kind (PascalCase).
# Apply with `drasi apply -f`, never `kubectl apply`.
apiVersion: v1
kind: Source
name: order-events-east
spec:
  kind: EventHub
  properties:
    host: eh-east.servicebus.windows.net
    eventHubs: [Order]
---
# drasi-west: same shape, different regional namespace
apiVersion: v1
kind: Source
name: order-events-west
spec:
  kind: EventHub
  properties:
    host: eh-west.servicebus.windows.net
    eventHubs: [Order]
```

**Critical**: Source state (consumer group offset, query cache, reaction execution state) is **not** replicated across regions. Each region's Drasi platform maintains independent state. Do **NOT** attempt to share source state across regions, this causes silent deduplication skips and missed events.

### Query aggregation (optional)

If you need to query across regions, for example, "how many active orders exist globally right now?", wire a **separate stateless query coordinator** service that calls each region's Drasi Query API and aggregates results:

```csharp
// Pseudo-code: multi-region query coordinator
async Task<AggregatedResult> GetGlobalOrderCount()
{
    var tasks = new[] {
        drasi_east.Query("MATCH (o:Order) RETURN COUNT(o) as count"),
        drasi_west.Query("MATCH (o:Order) RETURN COUNT(o) as count"),
        drasi_australia.Query("MATCH (o:Order) RETURN COUNT(o) as count"),
    };
    var results = await Task.WhenAll(tasks);
    return new AggregatedResult { Total = results.Sum(r => r.count) };
}
```

This pattern keeps each region's Drasi platform independent while allowing logical cross-region views.

### Multi-region reaction patterns

Reactions (HTTP, SignalR, event publishing) run **per region** but may need to fan-out globally:

```yaml
# Reaction: when an order ships, notify the customer (in all regions)
apiVersion: v1
kind: ConfigMap
metadata:
  name: drasi-reaction-shipment-notify
data:
  reaction.yaml: |
    reaction:
      name: order-shipped-notify
      type: http
      trigger:
        query: "MATCH (s:Shipment)-[:for_order]->(o:Order) RETURN s, o"
      action:
        method: POST
        url: "https://fulfillment-service/notify"
        payload:
          orderId: "{{ o.id }}"
          shipmentId: "{{ s.id }}"
          timestamp: "{{ s.timestamp }}"
```

The fulfillment service receives the shipment event and **deduplicates across regions** using an idempotency key:

```csharp
// Fulfillment service: dedup across regions
[HttpPost("/notify")]
public async Task HandleShipment([FromBody] ShipmentNotification shipment)
{
    var idempotencyKey = $"shipment-{shipment.orderId}-{shipment.shipmentId}-{shipment.timestamp}";
    
    // Dedup: store idempotency key in distributed cache (Redis Enterprise Active-Active)
    if (await cache.ExistsAsync(idempotencyKey))
        return Ok("Already processed"); // Duplicate from another region
    
    await cache.SetAsync(idempotencyKey, "processed", expiry: TimeSpan.FromMinutes(5));
    
    // Fan-out to the customer for this order (in all regions)
    await notificationHub.SendToOrder(shipment.orderId, shipment);
}
```

### Component image availability verification (pre-1.0 trap)

Not all Drasi component images are published at every platform tag (e.g. at 0.10.0, `reaction-http` and `reaction-signalr` exist but `reaction-post-dapr-pubsub` stops at 0.9.2). Before pinning a platform version, run the registry manifest check from `## Capability and Runtime Verification Gate` step 3 for **every** component you plan to use; missing components cause silent pod failures (`ImagePullBackOff`).

### Pre-1.0 stability: version downgrade consequences

Drasi is pre-1.0 (currently 0.10.x). **Cross-minor downgrades wipe all state** and are a full migration, not a rollback: 0.9.x uses MongoDB + Redis with `kubernetes-provider` / `api` / `query-container`; 0.10.x is Redis-only with `control-plane` / `query-host` / `view-svc` / `resource-provider`. Pin the platform version explicitly, do not float minor versions, and see `bundles/recovery/guide.md` `## Cross-version downgrade is not a simple reinstall` before any downgrade.

### Monitoring and health checks

For each region's Drasi instance, monitor:

```yaml
# Prometheus scrape config for Drasi metrics (if exposed)
- job_name: 'drasi-east'
  static_configs:
    - targets: ['drasi-east.system:9090']
  
- job_name: 'drasi-west'
  static_configs:
    - targets: ['drasi-west.system:9090']
```

Alert on:
- **Source lag**: consumer group offset drift (Event Hub source behind by >1 minute)
- **Query latency**: p99 query execution time > 5s (indicates resource contention)
- **Reaction error rate**: >1% of reactions failing
- **Version skew**: any two regions on different Drasi versions (enforce synchronized upgrades)

### Deployment stamp per region

Each region's Drasi stack is deployed via azd + Bicep:

```bicep
// bicep/modules/drasi-region/main.bicep
param region string // 'east', 'west', 'australia'
param drasi_version string // e.g., '0.10.0'
param cosmos_endpoint string
param event_hub_connection_string string

resource drasi_namespace 'kubernetes' = {
  // Deploy Drasi platform for this region
  // Pinned to drasi_version, scoped to region-local Event Hub, Cosmos replica
}
```

Deploy all regions simultaneously (not canary) to avoid observer/subscriber mismatch during rolling updates.

Adjacent verification sources:

- [Drasi documentation](https://drasi.io/)
- [Drasi project releases](https://github.com/drasi-project/drasi-platform/releases)
- [Drasi community engagement and governance](https://github.com/drasi-project/community)
- [Drasi for Kubernetes installation guides](https://drasi.io/drasi-kubernetes/how-to-guides/installation/)
- [Drasi source configuration how-tos](https://drasi.io/drasi-kubernetes/how-to-guides/configure-sources/)
- [Azure Event Hub consumer groups](https://learn.microsoft.com/azure/event-hubs/event-hubs-features#consumer-groups)
- [Cosmos DB multi-region replication](https://learn.microsoft.com/azure/cosmos-db/global-dist-under-the-hood)
- [Drasi vs Event-Driven Technologies](references/drasi-vs-event-driven.md) — decision framework for choosing Drasi vs Kafka/Event Hubs/polling
- [Schema Evolution and Production Failure Patterns](references/schema-evolution-and-failure-patterns.md) — handling source schema changes and common production failure patterns
- [Microsoft Fabric Real-Time Intelligence what's new](https://learn.microsoft.com/fabric/fundamentals/whats-new#real-time-intelligence-in-microsoft-fabric)
- [Azure Developer CLI reference](https://learn.microsoft.com/azure/developer/azure-developer-cli/reference)

## Runtime decision gate

Before authoring or changing anything, identify the runtime form:

| Runtime form | Use when | Primary bundles |
| --- | --- | --- |
| Drasi Server | Standalone server, process, Docker, or Azure Container Apps-hosted API. | `drasi-server`, `azure-hosting`, `security`, `validation`, `operations` |
| Drasi for Kubernetes | Drasi installed into a Kubernetes or AKS cluster and managed through `drasi` CLI resources. | `sources`, `continuous-queries`, `reactions`, `operations`, `recovery` |
| drasi-lib | Embedded Rust library or in-process use inside a Rust application. | `drasi-lib`, `currency-and-ai-context`, `validation`, `synthetic-user-testing` |

Do not mix resource shapes between runtimes. Kubernetes YAML does not automatically apply to Drasi Server, and Drasi Server REST payloads do not automatically apply to Drasi for Kubernetes.

## Mixed-runtime projects

Some projects span more than one Drasi runtime form. Treat this as a deliberate architectural choice with explicit cross-runtime constraints - not as "pick one runtime and use the others incidentally". Single-runtime projects skip this section.

**Supported composition patterns**

| Pattern | Edge | Hub | Transport | Use when |
| --- | --- | --- | --- | --- |
| drasi-lib edge → Drasi Server hub | drasi-lib embedded in a per-tenant or per-device Rust service | Drasi Server (Docker / ACA) | HTTP, gRPC, or queue (Event Hub, Kafka) | Edge nodes need in-process change detection with low latency; results aggregate to a central hub for cross-tenant queries or shared reactions. |
| Drasi for Kubernetes core + drasi-lib worker | Drasi for Kubernetes for shared sources/queries/reactions | drasi-lib worker for a single-purpose, latency-sensitive embedded path | HTTP webhook or queue | A specific workload needs in-process semantics (lowest possible latency, no network hop) while the rest of the project lives in the cluster. |
| Drasi Server side + Drasi for Kubernetes hub | Drasi Server (per-environment, per-team) | Drasi for Kubernetes (shared cluster) | HTTP or Event Grid | Teams own per-environment Drasi Server deployments that feed into a shared Kubernetes Drasi for cross-team queries. |

**Cross-runtime constraints (all four are non-negotiable for mixed projects)**

1. **One `versions.md`, one set of pins.** A mixed-runtime project has a single `versions.md` (from `templates/drasi-version-pinning.md`) - never per-runtime drift. Populate the "Cross-runtime compatibility" section in that template: shared drasi-core version line, shared apiVersion / result-contract assumption, shared MCP spec revision if either side exposes MCP, and the single `versions.md` location. CI MUST verify drasi-lib crate and Drasi Server / Platform image digest resolve to compatible drasi-core lines.
2. **Runtime-neutral query authoring.** ContinuousQueries that run on more than one runtime form MUST stay within the runtime-neutral feature subset documented in `bundles/continuous-queries/guide.md` "Cross-runtime portability". Set `queryLanguage` explicitly; project only scalar fields; verify time-window and GQL functions exist at the pinned release on every target. Forking a query per runtime is a design defect.
3. **End-to-end SLO and recovery sequencing.** Per-runtime SLOs are not additive across a runtime boundary. Set an explicit end-to-end freshness / RTO / RPO budget and decompose it per hop - see `bundles/observability/guide.md` "Cross-runtime end-to-end signals" and `bundles/recovery/guide.md` "Cross-runtime recovery and upgrade sequencing". Propagate W3C `traceparent` across every cross-runtime call; alert on end-to-end latency, not per-runtime in isolation.
4. **One MCP spec revision per project.** If two runtimes expose MCP (e.g. a Drasi MCP Reaction on the hub and an agent endpoint on the edge), both MUST pin the same MCP spec revision. Mixing MCP revisions across runtimes in one project is a sev-2 design defect - record any exception in the `versions.md` "Approved exceptions" table.

Cross-reference: `templates/drasi-version-pinning.md` "Cross-runtime compatibility"; `bundles/continuous-queries/guide.md` "Cross-runtime portability"; `bundles/observability/guide.md` "Cross-runtime end-to-end signals"; `bundles/recovery/guide.md` "Cross-runtime recovery and upgrade sequencing"; `bundles/scaling-and-capacity/guide.md` for per-runtime sizing inputs that must be applied per leg before declaring an end-to-end capacity budget.

## Do not use this skill for

- Generic Kubernetes, AKS, Azure Container Apps, Rust, API, or DevOps work where Drasi is not involved.
- General event-driven architecture advice unless Drasi is being considered, designed, implemented, validated, or operated.
- Generic MCP server design unless Drasi MCP Reaction, Drasi-fed agent resources, or Drasi query-result subscriptions are part of the task.
- Database CDC setup unless the CDC is being used for a Drasi Source or the Drasi design depends on it.
- Generic business, product, roadmap, or documentation work that does not need Drasi-specific guidance.

## Freshness and version conflict rules

- If the checked date is more than 30 days old, treat all versions, schemas, CLI commands, provider lifecycle notes, API paths, examples, and identity guidance as stale until re-verified.
- If official Drasi AI context, product docs, GitHub releases, crates.io, docs.rs, or live OpenAPI disagree, record the conflict and choose the source that matches the target runtime and stability requirement.
- For `drasi-lib`, do not automatically treat the newest crates.io/docs.rs crate as the recommended stable baseline when the official Drasi AI context or getting-started docs still point to an older line. Pin deliberately and document the trade-off.
- For MCP, verify both the Drasi MCP Reaction docs and the current MCP transport/security guidance before exposing endpoints or documenting client behaviour.

## Anti-Hallucination Rule (MANDATORY before writing Drasi code, YAML, or REST calls)

Drasi ships in three runtime forms that share branding but do NOT share APIs: **Drasi Server** (REST + container image, separate `apiVersion` family), **Drasi for Kubernetes** (CLI + Kubernetes-style YAML resources via the `drasi-platform` release line), and **drasi-lib** (embedded Rust crate). Resource schemas, CLI verbs, REST payload shapes, Source/Reaction provider catalogues, identity options, MCP spec revision, and result-contract fields are NOT symmetric between runtimes. The official Drasi AI context, `drasi-platform` GitHub releases, crates.io/docs.rs, and the upstream README quickstart can also disagree. `drasi-lib` is mid-rewrite for "Replayable Sources / Resumable Reactions" with an upcoming API break.

Before writing any Drasi `apiVersion`, `kind`, Source/Reaction provider name, ContinuousQuery field, CLI verb, REST endpoint path, `drasi-lib` type, or MCP spec revision string, ground each identifier against the pinned runtime using one of these methods, in order of preference:

1. **Official Drasi AI context** (currency anchor): fetch `drasi-context.yaml` from the official docs site and treat it as the authoritative inventory of providers, resource kinds, CLI verbs, and version pins for the release line you are targeting. Do not write resource YAML or REST payloads without first reconciling against this file.

2. **Live runtime introspection** (when the runtime is reachable):
   - Drasi Server: query the live OpenAPI document and `/health` endpoint of the pinned image digest. Example: `curl http://localhost:8080/api/v1/openapi.json` (and `curl http://localhost:8080/health`) against `ghcr.io/drasi-project/drasi-server@sha256:<digest>`. Do not infer endpoints from the README.
   - Drasi for Kubernetes: run `drasi list source`, `drasi list query`, `drasi list reaction`, and `drasi describe <kind> <name>` against the target cluster. Verify provider names, resource `apiVersion`, and status fields from live output.
   - drasi-lib: run `cargo doc --open` against the pinned crate version, or inspect `target/doc/drasi_lib/index.html`. Confirm type names, generic arity, and trait names from the generated docs of the version pinned in `Cargo.toml`.

3. **Release manifests**: cross-check the `drasi-platform` GitHub release notes, crates.io for `drasi-lib`, and the GHCR tag for `drasi-server@sha256:<digest>` against the AI context file. If they disagree, record the conflict and prefer the source that matches the target runtime and stability requirement (see `## Freshness and version conflict rules`).

4. **MCP spec revision**: do not write Drasi MCP Reaction client or server code without first reading the Drasi MCP Reaction docs to confirm the pinned MCP spec revision. As of the current verification snapshot Drasi pins `2025-03-26` while upstream MCP is `2026-07-28` - three revisions behind. Verify both sides before implementation.

Forbidden shortcuts when writing Drasi artifacts:

- Do not port resource YAML, `apiVersion`, or `kind` between Drasi Server REST payloads and Drasi for Kubernetes manifests. They are separate schemas.
- Do not assume a Source or Reaction provider that exists in Drasi for Kubernetes also exists in Drasi Server, or vice versa. Provider catalogues diverge.
- **Do not assume a provider listed by `drasi list reactionprovider` / `sourceprovider` has a published container image at the platform version tag.** The catalog and image builds are decoupled. Verify the image exists on GHCR before writing YAML, see `## Capability and Runtime Verification Gate` step 3 for the verification command.
- Do not assume drasi-lib types, traits, or generic arity match the conceptual model in Drasi Server / Kubernetes resources. The embedded Rust surface is its own API.
- Do not pin `drasi-lib` to the newest crates.io minor without reconciling against the official Drasi AI context and `drasi-core` rewrite status. This is a deliberate three-way pinning decision (see `bundles/drasi-lib/guide.md`).
- Do not use floating tags (`:latest`) for Drasi Server in any non-throwaway scenario. Resolve to an immutable `@sha256:` digest, then re-verify the digest exists on GHCR.
- Do not write more than one resource, query, or `drasi-lib` integration file against an unfamiliar Drasi version before running the runtime's validation step (`drasi describe`, Drasi Server `/health` + a sample REST POST, or `cargo check`).
- Do not write Microsoft Entra Workload ID configuration for a Drasi provider without first verifying that the specific provider supports the `identity` field. Verified providers at Drasi for Kubernetes 0.10.0: PostgreSQL Source, Azure Event Hub Source, SQL Server Source, Dataverse Source, Event Grid Reaction, SignalR Reaction. For Drasi for Kubernetes on AKS, **source and reaction pods use per-resource service accounts**, `source.<source-name>` and `reaction.<reaction-name>` respectively (verified against Drasi for Kubernetes 0.10.0), NOT the `default` service account as previously documented. The federated credential subject is `system:serviceaccount:<drasi-namespace>:<source|reaction>.<resource-name>`. Annotate that service account with `azure.workload.identity/client-id` and label it `azure.workload.identity/use=true` **after** `drasi apply` creates it (the SA does not exist until the resource is applied), then restart pods to pick up the annotation. The `identity` field is a top-level `spec` field, not inside `spec.properties`. For EventHub Sources specifically, the hub entity name MUST match the Cypher node label used in queries (`MATCH (m:Match)` requires hub named `Match`).
- **Do not downgrade Drasi for Kubernetes across minor versions without treating it as a full migration.** 0.9.x and 0.10.x have different state stores (MongoDB+Redis vs Redis-only) and different control-plane components. Cross-minor downgrade wipes all sources/queries/reactions/state. See `bundles/recovery/guide.md` `## Cross-version downgrade is not a simple reinstall`.

Known asymmetry traps (illustrative, verify each against the pinned runtime):

- PostgreSQL and Kubernetes Sources currently document **delete/recreate** modification behavior; SQL Server Source documents **re-applying the same source name** to modify. Do not write a single "update Source" recipe - the operation is provider-specific.
- Drasi Server REST endpoints (sources, queries, reactions, health, OpenAPI, interactive docs) are a separate API surface from the `drasi` CLI used for Drasi for Kubernetes; verb names and payload shapes do not map 1:1.
- The official AI context baseline (`drasi-lib 0.8.6` as of context 0.7.0), any newer crates.io/docs.rs line, and the in-flight `drasi-core` rewrite each expose potentially different API surfaces for Replayable Sources and Resumable Reactions. Confirm the pinned version's surface before writing embedded Rust code.
- ContinuousQuery `queryLanguage` (Cypher vs GQL), time-window function names, and scalar function availability vary per runtime and per release. Set `queryLanguage` explicitly and verify each function exists in the pinned release on every target runtime when authoring cross-runtime queries.
- The Drasi MCP Reaction pins MCP spec `2025-03-26`; agent endpoints elsewhere in the same project may pin a newer revision (upstream Latest Stable is `2026-07-28`). Mixing MCP revisions across runtimes in one project is a sev-2 design defect (see `## Mixed-runtime projects` constraint 4).
- **Provider catalog and image builds are decoupled.** `drasi list reactionprovider` (and `sourceprovider`) returns every provider definition bundled into the `drasi init` release, but the matching container image on GHCR may not have been built for that release line. A provider appearing in the catalog is NOT evidence its image exists at the platform version tag. For example, the `PostDaprPubSub` reaction provider IS registered under Drasi for Kubernetes 0.10.0 and fully documented at drasi.io, but `ghcr.io/drasi-project/reaction-post-dapr-pubsub:0.10.0` does NOT exist on GHCR (the tag stops at `0.9.2`). **The fix is NOT to downgrade the platform.** Drasi supports `externalImage: true` on the provider `spec.services.<service>` definition, when set, the `image` field is used verbatim (fully-qualified) instead of being resolved as `{ACR}/drasi-project/{image}:{IMAGE_VERSION_TAG}`. Register a custom provider pointing at the version tag that does exist (e.g. `image: ghcr.io/drasi-project/reaction-post-dapr-pubsub:0.9.2` with `externalImage: true`), then apply your reaction against that provider. Always verify the concrete image tag exists on the registry first, see the verification command in `## Capability and Runtime Verification Gate` step 3.
- **Drasi for Kubernetes has breaking architecture changes across minor versions.** 0.9.x uses MongoDB + Redis with `kubernetes-provider`/`api`/`query-container`. 0.10.x uses Redis-only with `control-plane`/`query-host`/`view-svc`/`resource-provider`. Cross-minor downgrade is a full migration, not a reinstall. See `bundles/recovery/guide.md` `## Cross-version downgrade is not a simple reinstall`.
- **Per-resource service accounts, not `default`.** Drasi for Kubernetes on AKS creates per-source SAs (`source.<source-name>`) and per-reaction SAs (`reaction.<reaction-name>`), not the `default` SA. The federated credential subject must match these names exactly. The SAs are created by `drasi apply`, annotate them with Workload Identity labels AFTER applying, then restart pods. See `bundles/sources/guide.md` and `bundles/reactions/guide.md` `## Reaction workload identity on AKS`.

### Safe degraded output when verification is blocked

If every verification method listed above is unavailable - no `drasi-context.yaml` reachable, no Drasi cluster or Drasi Server endpoint, no `drasi` CLI on PATH, no `cargo doc` output for the pinned `drasi-lib`, no MCP tools, no internet - do not produce production-shaped Drasi YAML, REST payloads, or `drasi-lib` Rust code from training-data memory. Drasi's three runtimes diverge enough that fabricated `apiVersion`, `kind`, provider names, and query functions will be rejected at `drasi apply`, at REST POST time, or by the Rust compiler.

Instead, return:

1. **A clearly-labelled skeleton** with `[VERIFY]` markers on every unverified identifier (`apiVersion`, `kind`, top-level resource shape, provider name, `spec` field, secret-reference syntax, ContinuousQuery `queryLanguage` and function names, Reaction provider name and properties, MCP spec revision string, identity configuration, `drasi-lib` types and traits). Mark every snippet as illustrative, not runnable.
2. **The exact verification commands** the caller must run before applying: the `drasi-context.yaml` fetch URL, `drasi list source` / `drasi list query` / `drasi list reaction` / `drasi describe <kind> <name>` against the target cluster, `curl http://<host>:8080/api/v1/openapi.json` against the pinned Drasi Server image digest, or `cargo doc --open` against the pinned `drasi-lib` version. Name the GHCR tag, the `drasi-platform` release, or the crates.io version the caller must pin.
3. **A list of every identifier you would have guessed**, grouped by failure mode (rejected at `drasi apply` / rejected at REST POST / rejected by `cargo check` / silently wrong behaviour at query time / silently wrong reaction payload). Call out cross-runtime asymmetry explicitly - say which runtime form (Server / Kubernetes / drasi-lib) the skeleton targets.
4. **An offer to produce a design-level artifact** instead - Source/Query/Reaction topology, result-contract specification, identity and secret matrix, end-to-end SLO budget, recovery sequencing plan, MCP spec revision decision record - that does not require verified identifiers.

Do not satisfy a user prompt of "write the YAML you would write if asked to ship this" by writing speculative Drasi resources under blocked verification. Fabricated `apiVersion: v1` or invented query functions are the most likely outcome, and the resulting pipeline will silently never fire.

## Multi-Region Drasi Coordination Patterns (High-Scale)

**Discovery context**: At high scale (large concurrent user bases, many parallel event streams, global event windows), Drasi must be deployed per-region to satisfy data-residency constraints and latency budgets. This section documents the architecture that emerged from production testing against Drasi for Kubernetes 0.10.0 and the critical gaps between theoretical multi-region guidance and runtime behaviour.

### Region-Local Source and Reaction Deployment

**Principle**: Each region's Drasi platform instance watches its own Cosmos DB regional replica. Sources, queries, and reactions are region-local, they do NOT share state across regions. This is the only deployment pattern that prevents silent data inconsistency at high scale.

**Architecture pattern**:
```yaml
# US-East region
regions:
  us-east:
    drasi:
      namespace: drasi-platform-us
      eventHub:
        name: event-hub-us-east
        consumerGroup: drasi-us-east
      cosmosSource:
        endpoint: "https://<account>-us-east.documents.azure.com/"
        database: "<app-db>"
        containers:
          - "orders"
          - "customers"
    sourceConfig:
      - apiVersion: v1
        kind: Source
        name: order-source-us
        spec:
          kind: EventHub
          properties:
            host: event-hub-us-east.servicebus.windows.net
            eventHubs: [Order]

  eu-west:
    drasi:
      namespace: drasi-platform-eu
      eventHub:
        name: event-hub-eu-west
        consumerGroup: drasi-eu-west
      cosmosSource:
        endpoint: "https://<account>-eu-west.documents.azure.com/"
        database: "<app-db>"
        containers:
          - "orders"
          - "customers"
    sourceConfig:
      - apiVersion: v1
        kind: Source
        name: order-source-eu
        spec:
          kind: EventHub
          properties:
            host: event-hub-eu-west.servicebus.windows.net
            eventHubs: [Match]
```

**Why per-region, not global state**:
1. **Data residency**: user PII (preferences, time zones, notification settings) must stay in the user's originating region per GDPR Article 5 and data-sovereignty requirements.
2. **Latency budget**: Drasi reactions (push notifications, AI explanations) must complete within <5 seconds. Cross-region state queries add 50–100ms per round-trip.
3. **Failure isolation**: A Drasi cluster failure in one region must not stall queries in another region. Global queries create a single point of failure.
4. **Cosmos consistency mode**: Multi-region writes require `Session` or `Strong` consistency for entity identity uniqueness. Drasi change-feed latency becomes linear with consistency mode, `Session` is the practical minimum for high-concurrency workloads.

**Source behaviour across regions**:
- Each region's Drasi platform creates its own `Source` resource with region-local Event Hub connection string or Cosmos DB endpoint.
- The `Source` reads only from that region's replica. There is NO cross-region fan-out or aggregation inside a single Source.
- Sources are **independent and must not share state**. A single global Source definition applied to multiple regional clusters will cause cache-incoherence bugs, each region's Drasi will build its own in-memory change-tracking state, creating divergent views of the same data source.

### Cross-Region Aggregation: Query-Side Only

**Principle**: Queries MAY span regions if an explicit cross-region aggregation service exists. Reactions MUST remain region-local (no cross-region notification fan-out).

**Pattern**:
```yaml
# Within a single region's Drasi platform:
apiVersion: v1
kind: ContinuousQuery
name: match-state-us-east
spec:
  queryLanguage: Cypher
  sources:
    subscriptions:
      - id: order-source-us
  query: |
    MATCH (o:Order)
    WHERE o.status = 'active'
      AND o.updatedAt > datetime.realtime() - duration({ minutes: 5 })
    RETURN o.id, o.customer, o.region, o.total, o.itemCount

# For cross-region aggregation, use an external service:
# DO NOT write a Drasi query that spans multiple Event Hub Sources or Cosmos replicas.
# Instead, use a region-local stateful aggregation service (e.g., an actor/grain
# or any idempotent stateful service) as the aggregator:
# - Each region's Drasi reacts to orders in its region
# - Each reaction posts order updates to a region-local aggregation service
# - The aggregation service persists to global Cosmos (state is multi-region write)
# - Cross-region consumers read from the aggregation service, not directly from Drasi
```

**Why aggregation service, not multi-region queries**:
- Drasi for Kubernetes sources are inherently region-scoped (one connection string, one Event Hub, one Cosmos endpoint per source).
- Writing a query that joins across two Event Hub Sources in different regions creates a "distributed query" that has no unified backpressure model, one region's lag cascades to the other.
- At high scale, per-region Drasi deployments must shed load independently. Cross-region queries introduce dependency chains that break independent blast-radius limits.

**Verified aggregation layer**: Use a region-local stateful aggregation service (e.g., an actor/grain or any idempotent stateful service) as the aggregation fabric. Each region's Drasi Reactions invoke the aggregation service (region-local instance). Aggregation state is persisted to multi-region Cosmos, so cross-region readers (other service instances, APIs) get consistent state without Drasi having to coordinate across regions.

### Per-Component Image Availability Verification (Critical Gap)

**Discovery**: Drasi component container images are NOT published for every component at every version tag. The `drasi list reactionprovider` / `sourceprovider` command and the official documentation both list providers that have no corresponding container image on GHCR.

**Verified incident**: At `drasi-platform` version 0.10.0:
- `reaction-post-dapr-pubsub` IS listed in `drasi list reactionprovider`
- `ghcr.io/drasi-project/reaction-post-dapr-pubsub:0.10.0` DOES NOT exist on GHCR
- The image stops at tag `0.9.2`
- Attempting to deploy the reaction with platform 0.10.0 fails silently or causes pod CrashLoopBackOff

**Mandatory verification before pinning Drasi platform version**:

```bash
# Step 1: List all providers in the target platform version
drasi list reactionprovider
drasi list sourceprovider

# Step 2: For each provider you plan to use, verify the image exists on GHCR using the
# token-authenticated manifest check from `## Capability and Runtime Verification Gate`
# step 3. GHCR requires a pull-scope bearer token even for public images — an anonymous
# curl of the manifest endpoint (or grepping its response body) is not a valid check.

# Step 3: If image MISSING, do NOT upgrade to that platform version without a mitigation
# Mitigation option: use externalImage field to point to the version that DOES exist
# (See the Anti-Hallucination Rule section above for externalImage example)
```

**Production guidance**: Before every Drasi platform version upgrade, run the verification script for every Source and Reaction provider you intend to use. Record the verification output in your deployment artifact as evidence. If an image is missing and you cannot use `externalImage`, **do not upgrade**, defer the upgrade until a platform release includes the missing component.

### Pre-1.0 Stability and Cross-Minor Downgrade Risk

**Status**: Drasi for Kubernetes is pre-1.0 (currently at 0.10.0). Breaking changes occur between minor versions.

**Cross-minor downgrade is a full migration, not a rollback**:
- **0.9.x**: State store is MongoDB + Redis. Components are `kubernetes-provider`, `api`, `query-container`.
- **0.10.x**: State store is Redis-only. Components are `control-plane`, `query-host`, `view-svc`, `resource-provider`.
- **0.9.x → 0.10.x migration**: Manual: export sources/queries/reactions from 0.9.x via `drasi describe`, apply to 0.10.x platform, rebuild Redis state.
- **0.10.x → 0.9.x downgrade**: Full reset. MongoDB state is gone. Redis state from 0.10.x is incompatible with 0.9.x components.

**Production constraint for high-scale deployments**:
- Pin Drasi for Kubernetes to the **first stable release** of 1.0 or later before deploying at high scale.
- 0.10.x is supported for pre-production validation only.
- Before committing to a 1.x release, verify it has been tested for at least 30 days in production environments handling sustained high-throughput event streams and <5s query latency on >100 concurrent queries.
- Document your chosen release in an Architecture Decision Record with a six-month review gate.

**Monitoring guidance**: Track CNCF Sandbox adoption metrics (contributor count, production deployments, time-since-release) for Drasi. If adoption metrics decline or major version releases stall for >90 days, escalate to the architecture team. Drasi may be entering maintenance-only mode.

### SLO Budget Impact: Multi-Region Drasi Deployments

**SLO allocation**: At high scale, Drasi is responsible for <500ms of the overall end-to-end notification delivery SLO (source change → Drasi reaction → aggregation handler → downstream notification service).

**Per-region impact when Drasi stalls**:
- If Drasi in one region (e.g., US-East) stops firing reactions for >30 seconds, that region's SLO budget burns at 1 budget unit per second for all subscribers in that region.
- If Drasi in ALL regions stalls simultaneously, system-wide SLO budget exhaustion in <5 minutes.

**Recommended monitoring**:
- Alert if Drasi query latency p99 > 2 seconds (per region).
- Alert if Drasi reaction fire rate drops below expected events/minute baseline (e.g., <1000 reactions/minute during active matches).
- Alert if Event Hub consumer lag (Drasi consumer group) exceeds 30 seconds.
- Dashboard: reaction fire latency (from Event Hub receive to reaction POST) - should be <500ms p99.

**Graceful degradation**: If Drasi in one region is stalled:
1. The aggregation service falls back to direct push notifications (no Drasi-enhanced context, basic event data only).
2. Notify SRE team to investigate Drasi platform health.
3. Do NOT attempt to failover Drasi reaction workload to another region, each region's Drasi is bound to its Cosmos replica and cannot process events from other regions.

### Workload Identity on AKS: Per-Resource Service Accounts

**Discovery**: Drasi for Kubernetes on AKS creates service accounts per source and per reaction, NOT using the `default` service account as previously documented.

**Verified behaviour at drasi-platform 0.10.0**:
- When you apply a Source named `order-source-us` (canonical shape: `apiVersion: v1`, `kind: Source`, top-level `name:`, applied with `drasi apply`), Drasi creates a service account named `source.order-source-us` in the Drasi namespace.
- When you apply a `Reaction` for Event Grid, Drasi creates a service account named `reaction.event-grid-notifier`.
- These service accounts are created by the Drasi platform controller, they do NOT exist before `drasi apply`.

**Workload Identity setup sequence**:
```bash
# Step 1: Apply Drasi sources and reactions with the Drasi CLI (NOT kubectl apply).
# The per-resource service accounts are created by drasi apply.
# NAMESPACE defaults to drasi-system; substitute your Drasi namespace.
drasi apply -f sources.yaml    # Creates service account source.<source-name>
drasi apply -f reactions.yaml  # Creates service account reaction.<reaction-name>

# Step 2: Wait for service accounts to be created (may take 5-10 seconds)
kubectl get sa -n <drasi-namespace> | grep source.
kubectl get sa -n <drasi-namespace> | grep reaction.

# Step 3: Annotate each service account with the Workload Identity client ID
kubectl annotate serviceaccount source.order-source-us \
  -n <drasi-namespace> \
  azure.workload.identity/client-id=<client-id-of-managed-identity> \
  --overwrite

kubectl annotate serviceaccount reaction.event-grid-notifier \
  -n <drasi-namespace> \
  azure.workload.identity/client-id=<client-id-of-managed-identity> \
  --overwrite

# Step 4: Label service accounts for Workload Identity
kubectl label serviceaccount source.order-source-us \
  -n <drasi-namespace> \
  azure.workload.identity/use=true \
  --overwrite

kubectl label serviceaccount reaction.event-grid-notifier \
  -n <drasi-namespace> \
  azure.workload.identity/use=true \
  --overwrite

# Step 5: Restart pods to pick up the new annotations
kubectl rollout restart deployment drasi-query-host -n <drasi-namespace>
kubectl rollout restart deployment drasi-resource-provider -n <drasi-namespace>
```

**Federated credential subject**: The federated credential must use the exact service account name:
```
system:serviceaccount:<drasi-namespace>:source.<source-name>
system:serviceaccount:<drasi-namespace>:reaction.<reaction-name>
```

**Event Hub Source special case**: The Event Hub entity name MUST match the Cypher node label used in queries:
```yaml
# Query uses the Event Hub name as the node label:
MATCH (m:Match)  # <- Node label is "Match" (the Event Hub name)
WHERE m.status = 'active'

# Event Hub source must list the hub name in eventHubs so it matches the Cypher
# label (case-sensitive; escape dashed hub names with backticks in Cypher):
apiVersion: v1
kind: Source
name: order-source-us
spec:
  kind: EventHub
  properties:
    host: <eventhub-namespace>.servicebus.windows.net
    eventHubs:
      - "Match"  # <- MUST match the Cypher label, case-sensitive
    # connectionString: only when NOT using Managed Identity; store as a Secret ref
```

**Impact on deployment**: After every source/reaction configuration change or Drasi platform upgrade, re-verify Workload Identity annotations are still in place and pods are running. Drasi controller may recreate service accounts during upgrades, annotations are NOT persisted by default.

## Bundle routing

Load the top-level skill first, then load only the bundle guides needed for the task.

| Task | Bundle |
| --- | --- |
| Azure Container Apps, `azd`, ingress, image, revision, managed identity, API exposure | `bundles/azure-hosting/guide.md` |
| Source provider setup, CDC prerequisites, credentials, provider lifecycle | `bundles/sources/guide.md` |
| ContinuousQuery authoring, Cypher/GQL, joins, result contract, query validation | `bundles/continuous-queries/guide.md` |
| Reaction setup, webhooks, Event Grid, SignalR, Debug, MCP, custom reactions | `bundles/reactions/guide.md` |
| Runtime status, inactive queries, no events, logs, CLI/API drift, triage, exposing reactions/sources via `drasi ingress init` | `bundles/operations/guide.md` |
| Logs, metrics, alerts, dashboards, SLOs, telemetry, operational evidence | `bundles/observability/guide.md` |
| Destructive recovery, reset, rebuild, rollback, incident-safe remediation | `bundles/recovery/guide.md` |
| Auth, network exposure, secrets, identity, supply chain, data minimization | `bundles/security/guide.md` |
| Post-deploy proof, test data, end-to-end evidence, release acceptance | `bundles/validation/guide.md` |
| CI/CD, GitOps, promotion, deployment order, release artifacts | `bundles/delivery/guide.md` |
| MCP resources, AI agent subscriptions, agent-facing contracts, consumer-side reference architecture, notification handler patterns | `bundles/agent-integration/guide.md` |
| Minimal examples and scaffold patterns | `bundles/examples/guide.md` |
| Local developer workflow, VS Code extension, Dev Containers, Codespaces, onboarding | `bundles/developer-experience/guide.md` |
| Drasi docs/releases, official AI context, version-sensitive schemas, anti-drift checks | `bundles/currency-and-ai-context/guide.md` |
| Synthetic user testing, Dev Container/Codespaces validation, tutorial/scaffold execution proof | `bundles/synthetic-user-testing/guide.md` |
| Scaling, capacity planning, load testing, HPA/KEDA, throughput, backpressure | `bundles/scaling-and-capacity/guide.md` |
| Embedded Rust applications using `drasi-lib` | `bundles/drasi-lib/guide.md` |
| Drasi Server standalone runtime: Web UI, REST API, Solution Templates, Instances, plugins, webhook mode | `bundles/drasi-server/guide.md` |
| Custom Source / Reaction authoring, plugin SDK, scalar/aggregating function extensions, query-language internals | `bundles/custom-plugins/guide.md` |

See `bundles/catalog.yaml` for machine-readable bundle metadata. Use `templates/` for reusable evidence, currency, architecture-decision, and risk-register outputs when a Drasi task needs a durable handoff.

## Prerequisites by runtime

Install once before Day-0 work. Pin versions; do not use shell installers that pull `main`.

| Runtime form | Required tooling | Verify |
| --- | --- | --- |
| Drasi Server | Docker (or a pinned Rust toolchain plus Node.js/npm for source builds — verify the current MSRV in the drasi-server README at the pinned tag before building). Optional: the `drasi-server` binary built locally or pulled from `ghcr.io/drasi-project/drasi-server` (pin by digest in production). | `docker run --rm -p 8080:8080 ghcr.io/drasi-project/drasi-server@sha256:<digest>` then `curl http://localhost:8080/health`. |
| Drasi for Kubernetes | `kubectl` matching the target cluster version, plus the `drasi` CLI for the target platform release. Install the CLI from a pinned release (`drasi-platform` GitHub releases or the official install script with an explicit version). For Azure: `az`, `azd`. | `drasi version` (CLI) and `drasi list source` against an empty namespace. |
| drasi-lib | Rust toolchain pinned in `rust-toolchain.toml`. Pin the `drasi-lib` crate version in `Cargo.toml` after resolving the Drasi AI context vs crates.io version conflict (see `currency-and-ai-context`). | `cargo check` and a smoke test that constructs a Drasi runtime in-process. |

Record the exact tool versions, image digests, and crate versions in your repo's `README` or a `versions.md` file so CI, scripts, and humans agree.

> **CLI environment state trap (Drasi for Kubernetes).** The `drasi` CLI persists its own environment config across sessions. After switching `kubectl` contexts to a new or different cluster, `drasi init` and other commands will silently target the *previously configured* cluster, not the current kubectl context. Before running `drasi init` (or any cluster-scoped command against a freshly switched cluster), always re-point the CLI at the current context:

```bash
kubectl config current-context   # confirm you are on the intended cluster
drasi env kube                    # re-bind the Drasi CLI to the current kubectl context
drasi init                        # only now safe to initialise
```

Symptom of the trap: `drasi init` reports success, but resources appear in the wrong cluster (or `drasi list source` returns unexpected results from the previous cluster).

## 90-minute starter path

Use this BEFORE the full Day-0 workflow below. The Day-0 workflow is for production-bound projects; this section gives a novice (or anyone with ~90 minutes) a concrete, runtime-specific path to a first working pipeline. Pick the sequence that matches your runtime form, then graduate to the Day-0 workflow when you commit to production.

Confirm bundle contents and CLI/REST shapes against the current release before copying examples.

### Drasi Server local (Docker) - first working pipeline

Outcome: a working source-to-reaction pipeline you can demo locally with one `curl`.

1. `bundles/examples/guide.md` - start with the "5-minute Hello Drasi" mini-example, then the stitched mock-source-to-log-reaction example.
2. `bundles/reactions/guide.md` - swap the Log/Debug reaction for an HTTP or SSE reaction so you can prove delivery to another process.
3. `bundles/operations/guide.md` - learn the inactive-query / no-events / drift triage paths so your local pipeline is debuggable.
4. (Optional) `bundles/validation/guide.md` - add an end-to-end change-to-effect proof before you call it done.

### Drasi for Kubernetes (kind / AKS) - first cluster pipeline

Outcome: a Source, ContinuousQuery, and Reaction running in a kind or AKS cluster with a synthetic change that produces a visible reaction effect.

1. `bundles/examples/guide.md` - read the "Minimal Drasi for Kubernetes flow" section for the create/delete order (Source -> ContinuousQuery -> Reaction; reverse for cleanup) and the minimal Source/ContinuousQuery/Reaction skeletons.
2. `bundles/sources/guide.md` - pick a provider, verify its lifecycle (some providers require delete/recreate to modify), and apply a Source.
3. `bundles/continuous-queries/guide.md` - author a Cypher query with an explicit result contract against that Source.
4. `bundles/reactions/guide.md` - wire a reaction (Debug or HTTP) to the query for a first visible effect.
5. `bundles/operations/guide.md` - confirm query active state, source readiness, and reaction delivery using `drasi list` / `drasi describe`-style commands; confirm exact CLI shape at the current release.

### drasi-lib (embedded Rust) - first in-process pipeline

Outcome: a Rust binary that constructs a Drasi runtime in-process, registers a Source and ContinuousQuery, and observes a reaction-equivalent callback.

If you just want to see it run, pin `drasi-lib = "0.8.6"` (the current version listed in the official Drasi AI context) and proceed; defer the AI-context-vs-crates.io version-conflict question until after the first green smoke test.

1. `bundles/currency-and-ai-context/guide.md` - read the version-conflict guidance (the official Drasi AI context currently lists `0.8.6`; crates.io/docs.rs may show newer) when you are ready to pin deliberately for production.
2. `bundles/drasi-lib/guide.md` - follow the embedded-Rust scaffolding pattern for the version you pinned.
3. `bundles/validation/guide.md` - write a smoke test that feeds a synthetic change and asserts on the query result.
4. (Optional) `bundles/synthetic-user-testing/guide.md` - wrap the scaffold in a repeatable execution proof if it is going to be reused.

## Non-negotiable rules

1. **Pin versions.** Do not use floating `latest` tags, unpinned CLI installs, or implicit provider versions for production examples.
2. **Use official context for AI-generated work.** For non-trivial or version-sensitive Drasi work, check the official Drasi AI context and product docs before generating code, examples, or docs.
3. **Verify provider schemas.** Check the current Drasi docs before generating Source, ContinuousQuery, Reaction, or Drasi Server payload schemas.
4. **Secure management APIs.** Do not expose Drasi management endpoints, OpenAPI, or docs publicly without an explicit auth and network boundary.
5. **Use dependency order.** Create in order: sources, queries, reactions. Delete or rollback in reverse order: reactions, queries, sources.
6. **Respect provider lifecycle differences.** Do not claim all resources can be modified with `apply`. Use the provider-specific lifecycle matrix in `sources`.
7. **Do not overstate managed identity.** Prefer Microsoft Entra Workload ID only when the selected provider explicitly documents `identity` support.
8. **Prove runtime behavior.** Infrastructure success is not enough. Validate the full acceptance chain: source change to query update to reaction effect.
9. **Treat destructive recovery as a controlled change.** Capture evidence, export state, confirm blast radius, and get explicit approval before reset, uninstall, namespace deletion, database slot deletion, or state purge.
10. **Minimize secrets and data exposure.** Use Key Vault or Kubernetes Secrets only as appropriate, redact logs, avoid raw payload logging, and rotate credentials.
11. **Prefer new-project defaults.** Use secure-by-default architecture, clean naming, automation, environment separation, repeatable validation, and least privilege.
12. **Pin via a versions manifest.** Capture pinned versions (image digest, CLI version, platform release, drasi-lib crate, MCP spec version, last-checked date) in `versions.md` using `templates/drasi-version-pinning.md`. CI MUST fail if any required field is missing or stale beyond the freshness window.
13. **Run preflight before triage loops.** For PostgreSQL sources, verify target schema tables and PKs in SQL before source/query debugging. For queries, compile a minimal operator/function preflight on the pinned runtime before applying full manifests.

## Day-0 workflow for new projects

1. Choose runtime form and deployment target, **then load all mandatory co-skills for that target** (see "Mandatory co-skills by deployment target" above). Do not proceed to step 2 until co-skills are loaded.
2. Pin Drasi Server, Drasi platform, CLI, provider, container, and action versions.
3. Select source systems and identity strategy per provider.
4. Define ContinuousQuery contracts before reactions.
5. Define reaction reliability expectations: retries, idempotency, backpressure, downstream authorization, and observable side effects.
6. Secure the control plane and reaction endpoints before exposing them.
7. Build observability for source lag, query health, reaction failures, downstream delivery latency, and capacity signals.
8. Build an end-to-end validation harness with synthetic data and expected query/reaction output.
9. Add a repeatable local developer path with CLI/script equivalents for important VS Code actions.
10. Add synthetic-user tests for reusable scaffolds, tutorials, and developer onboarding paths.
11. Define CI/CD promotion, rollback order, and recovery boundaries.
12. Capture currency, validation, capacity, developer-experience, architecture-decision, risk, and operational evidence in the PR or release notes.

## Evidence required before success

A Drasi task is not complete until the response or PR includes:

- Runtime form, checked documentation source, and pinned version evidence.
- Source readiness evidence.
- Query active or result evidence.
- Reaction delivery evidence, not only reaction creation.
- Security posture evidence for any exposed endpoint.
- Rollback or cleanup path.
- Capacity or scale evidence for production paths.
- Developer-experience evidence for new project scaffolds.
- Synthetic-user test evidence for reusable scaffolds or tutorials.
- Known residual risks, especially if a feature is pre-1.0, experimental, provider-specific, or MCP-facing.
- Architecture decision and risk-register entries for new reusable or production-targeted projects.
- Architecture decision record entry filled from `templates/drasi-architecture-decision-record.md`.
- Risk register entry filled from `templates/drasi-risk-register.md`.
- Threat model artifact filled from `templates/drasi-threat-model.md` for production paths.

## Resource Directories

Load these directories only when the selected workflow needs deeper examples, prompts, or reference material:

- [references/](references/)

## Final Output Contract

Every engagement using this skill produces:

- a runtime-specific Drasi recommendation with version and capability evidence for the target form;
- the relevant source, query, reaction, hosting, or recovery design guidance tied to the right Drasi bundles;
- validation expectations covering runtime health, reaction delivery, security posture, and rollback or cleanup path;
- explicit residual risks or `[VERIFY]` items for pre-1.0, provider-specific, or MCP-revision-sensitive behavior.

## Quality Gate

Do not sign off until the runtime form, provider behavior, version pins, and validation evidence are explicit, and no production-shaped manifest depends on unverified Drasi or MCP assumptions.

## Mandatory co-skills by deployment target

This is NOT optional. A Drasi deployment touches identity, networking, and messaging domains that live in sibling skills. Load the co-skills for your deployment target **before** authoring any resource, identity config, or networking manifest. Skipping these is how production deployments hit silent failures (wrong service account, wrong consumer group, wrong identity property path).

| Deployment target | Mandatory co-skills to load first | Why (the failure it prevents) |
| --- | --- | --- |
| Drasi for Kubernetes on **AKS** | `identity-managed-identity` (workload identity ordering + SA annotation), `aks-cluster-architecture` (identity, egress, node pools), `event-driven-messaging` (consumer groups, partitioning, idempotent consumers) | Workload Identity SA annotation ordering; kubelet identity ACR pull; Event Hub consumer group + label mapping |
| Drasi for Kubernetes on **other K8s** | `event-driven-messaging` | Consumer group, partitioning, idempotent consumer design |
| Drasi **Server on Azure Container Apps** | `azure-container-apps` (identity, ingress, revisions), `azure-deployment-preflight` (validation), `identity-managed-identity` if accessing Azure resources | Managed identity wiring, ingress exposure, deployment validation |
| Drasi **Server on Docker / standalone** | (none mandatory) | Local development — no cloud identity or networking domain |
| Any Drasi pipeline using **PostgreSQL / SQL Server sources** | `identity-managed-identity` (if Entra auth), database skill for that engine | CDC slot, credential rotation, Entra admin registration |
| Any Drasi pipeline using **Event Grid / SignalR / HTTP reactions** | `event-driven-messaging` | Delivery semantics, idempotency, retry, DLQ |

If a co-skill listed above is not present in the repository, note it as a gap, do not silently proceed without the guidance.
