---
name: aws-serverless-eda
description: AWS serverless and event-driven architecture expert based on Well-Architected Framework. Use when building serverless APIs, Lambda functions, REST APIs, microservices, or async workflows. Covers Lambda with TypeScript/Python, API Gateway (REST/HTTP), DynamoDB, Step Functions,...
risk: critical
source: https://github.com/zxkane/aws-skills/tree/main/plugins/serverless-eda/skills/aws-serverless-eda
source_repo: zxkane/aws-skills
source_type: community
date_added: 2026-07-01
license: MIT
license_source: https://github.com/zxkane/aws-skills/blob/main/LICENSE
---

# AWS Serverless & Event-Driven Architecture

This skill provides comprehensive guidance for building serverless applications and event-driven architectures on AWS based on Well-Architected Framework principles.

## AWS Documentation Requirement

Always verify AWS facts using MCP tools (`mcp__aws-mcp__*` or `mcp__*awsdocs*__*`) before answering. The `aws-mcp-setup` dependency is auto-loaded — if MCP tools are unavailable, guide the user through that skill's setup flow.

## Serverless MCP Servers

This skill leverages the CDK MCP server (provided via `aws-cdk-development` dependency) and AWS Documentation MCP for serverless guidance.

> **Note**: The following AWS MCP servers are available separately via the Full AWS MCP Server (see `aws-mcp-setup` skill) and are not bundled with this plugin:
> - AWS Serverless MCP — SAM CLI lifecycle (init, deploy, local test)
> - AWS Lambda Tool MCP — Direct Lambda invocation
> - AWS Step Functions MCP — Workflow orchestration
> - Amazon SNS/SQS MCP — Messaging and queue management

## When to Use This Skill

Use this skill when:
- Building serverless applications with Lambda
- Designing event-driven architectures
- Implementing microservices patterns
- Creating asynchronous processing workflows
- Orchestrating multi-service transactions
- Building real-time data processing pipelines
- Implementing saga patterns for distributed transactions
- Designing for scale and resilience

## AWS Well-Architected Serverless Design Principles

### 1. Speedy, Simple, Singular

**Functions should be concise and single-purpose**

```typescript
// ✅ GOOD - Single purpose, focused function
export const processOrder = async (event: OrderEvent) => {
  // Only handles order processing
  const order = await validateOrder(event);
  await saveOrder(order);
  await publishOrderCreatedEvent(order);
  return { statusCode: 200, body: JSON.stringify({ orderId: order.id }) };
};

// ❌ BAD - Function does too much
export const handleEverything = async (event: any) => {
  // Handles orders, inventory, payments, shipping...
  // Too many responsibilities
};
```

**Keep functions environmentally efficient and cost-aware**:
- Minimize cold start times
- Optimize memory allocation
- Use provisioned concurrency only when needed
- Leverage connection reuse

### 2. Think Concurrent Requests, Not Total Requests

**Design for concurrency, not volume**

Lambda scales horizontally - design considerations should focus on:
- Concurrent execution limits
- Downstream service throttling
- Shared resource contention
- Connection pool sizing

```typescript
// Consider concurrent Lambda executions accessing DynamoDB
const table = new dynamodb.Table(this, 'Table', {
  billingMode: dynamodb.BillingMode.PAY_PER_REQUEST, // Auto-scales with load
});

// Or with provisioned capacity + auto-scaling
const table = new dynamodb.Table(this, 'Table', {
  billingMode: dynamodb.BillingMode.PROVISIONED,
  readCapacity: 5,
  writeCapacity: 5,
});

// Enable auto-scaling for concurrent load
table.autoScaleReadCapacity({ minCapacity: 5, maxCapacity: 100 });
table.autoScaleWriteCapacity({ minCapacity: 5, maxCapacity: 100 });
```

### 3. Share Nothing

**Function runtime environments are short-lived**

```typescript
// ❌ BAD - Relying on local file system
export const handler = async (event: any) => {
  fs.writeFileSync('/tmp/data.json', JSON.stringify(data)); // Lost after execution
};

// ✅ GOOD - Use persistent storage
export const handler = async (event: any) => {
  await s3.putObject({
    Bucket: process.env.BUCKET_NAME,
    Key: 'data.json',
    Body: JSON.stringify(data),
  });
};
```

**State management**:
- Use DynamoDB for persistent state
- Use Step Functions for workflow state
- Use ElastiCache for session state
- Use S3 for file storage

### 4. Assume No Hardware Affinity

**Applications must be hardware-agnostic**

Infrastructure can change without notice:
- Lambda functions can run on different hardware
- Container instances can be replaced
- No assumption about underlying infrastructure

**Design for portability**:
- Use environment variables for configuration
- Avoid hardware-specific optimizations
- Test across different environments

### 5. Orchestrate with State Machines, Not Function Chaining

**Use Step Functions for orchestration**

```typescript
// ❌ BAD - Lambda function chaining
export const handler1 = async (event: any) => {
  const result = await processStep1(event);
  await lambda.invoke({
    FunctionName: 'handler2',
    Payload: JSON.stringify(result),
  });
};

// ✅ GOOD - Step Functions orchestration
const stateMachine = new stepfunctions.StateMachine(this, 'OrderWorkflow', {
  definition: stepfunctions.Chain
    .start(validateOrder)
    .next(processPayment)
    .next(shipOrder)
    .next(sendConfirmation),
});
```

**Benefits of Step Functions**:
- Visual workflow representation
- Built-in error handling and retries
- Execution history and debugging
- Parallel and sequential execution
- Service integrations without code

### 6. Use Events to Trigger Transactions

**Event-driven over synchronous request/response**

```typescript
// Pattern: Event-driven processing
const bucket = new s3.Bucket(this, 'DataBucket');

bucket.addEventNotification(
  s3.EventType.OBJECT_CREATED,
  new s3n.LambdaDestination(processFunction),
  { prefix: 'uploads/' }
);

// Pattern: EventBridge integration
const rule = new events.Rule(this, 'OrderRule', {
  eventPattern: {
    source: ['orders'],
    detailType: ['OrderPlaced'],
  },
});

rule.addTarget(new targets.LambdaFunction(processOrderFunction));
```

**Benefits**:
- Loose coupling between services
- Asynchronous processing
- Better fault tolerance
- Independent scaling

### 7. Design for Failures and Duplicates

**Operations must be idempotent**

```typescript
// ✅ GOOD - Idempotent operation
export const handler = async (event: SQSEvent) => {
  for (const record of event.Records) {
    const orderId = JSON.parse(record.body).orderId;

    // Check if already processed (idempotency)
    const existing = await dynamodb.getItem({
      TableName: process.env.TABLE_NAME,
      Key: { orderId },
    });

    if (existing.Item) {
      console.log('Order already processed:', orderId);
      continue; // Skip duplicate
    }

    // Process order
    await processOrder(orderId);

    // Mark as processed
    await dynamodb.putItem({
      TableName: process.env.TABLE_NAME,
      Item: { orderId, processedAt: Date.now() },
    });
  }
};
```

**Implement retry logic with exponential backoff**:
```typescript
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
    }
  }
  throw new Error('Max retries exceeded');
}
```

## Architecture Patterns

For detailed implementation patterns with full code examples, see the reference documentation:

### Event-Driven Architecture Patterns
**File**: `references/eda-patterns.md`
- Event Router with EventBridge (custom event bus, schema registry, rule-based routing)
- Queue-Based Processing with SQS (standard/FIFO, DLQ, Lambda consumers)
- Pub/Sub Fan-Out with SNS + SQS (multi-consumer, filtering)
- Saga Pattern with Step Functions (distributed transactions, compensating actions)
- Event Sourcing with DynamoDB Streams (append-only event store, projections)

### Serverless Architecture Patterns
**File**: `references/serverless-patterns.md`
- API-Driven Microservices (REST API + Lambda backend)
- Stream Processing with Kinesis (real-time, batch windowing, bisect on error)
- Async Task Processing with SQS (background jobs, concurrency control)
- Scheduled Jobs with EventBridge (cron/rate schedules)
- Webhook Processing (signature validation, async queue forwarding)

> **Important**: When using CDK code examples from references, avoid hardcoding resource names (e.g., `restApiName`, `eventBusName`). Let CDK generate unique names automatically to enable reusability and parallel deployments. See `aws-cdk-development` skill for details.

## Best Practices

### Error Handling

**Implement comprehensive error handling**:

```typescript
export const handler = async (event: SQSEvent) => {
  const failures: SQSBatchItemFailure[] = [];

  for (const record of event.Records) {
    try {
      await processRecord(record);
    } catch (error) {
      console.error('Failed to process record:', record.messageId, error);
      failures.push({ itemIdentifier: record.messageId });
    }
  }

  // Return partial batch failures for retry
  return { batchItemFailures: failures };
};
```

### Dead Letter Queues

**Always configure DLQs for error handling**:

```typescript
const dlq = new sqs.Queue(this, 'DLQ', {
  retentionPeriod: Duration.days(14),
});

const queue = new sqs.Queue(this, 'Queue', {
  deadLetterQueue: {
    queue: dlq,
    maxReceiveCount: 3,
  },
});

// Monitor DLQ depth
new cloudwatch.Alarm(this, 'DLQAlarm', {
  metric: dlq.metricApproximateNumberOfMessagesVisible(),
  threshold: 1,
  evaluationPeriods: 1,
  alarmDescription: 'Messages in DLQ require attention',
});
```

### Observability

**Enable tracing and monitoring**:

```typescript
new NodejsFunction(this, 'Function', {
  entry: 'src/handler.ts',
  tracing: lambda.Tracing.ACTIVE, // X-Ray tracing
  environment: {
    POWERTOOLS_SERVICE_NAME: 'order-service',
    POWERTOOLS_METRICS_NAMESPACE: 'MyApp',
    LOG_LEVEL: 'INFO',
  },
});
```

## Using MCP Servers Effectively

Use the CDK MCP server (via `aws-cdk-development` dependency) for construct recommendations and CDK-specific guidance when building serverless infrastructure.

Use AWS Documentation MCP to verify service features, regional availability, and API specifications before implementing.

## Additional Resources

This skill includes comprehensive reference documentation based on AWS best practices:

- **Serverless Patterns**: `references/serverless-patterns.md`
  - Core serverless architectures and API patterns
  - Data processing and integration patterns
  - Orchestration with Step Functions
  - Anti-patterns to avoid

- **Event-Driven Architecture Patterns**: `references/eda-patterns.md`
  - Event routing and processing patterns
  - Event sourcing and saga patterns
  - Idempotency and error handling
  - Message ordering and deduplication

- **Security Best Practices**: `references/security-best-practices.md`
  - Shared responsibility model
  - IAM least privilege patterns
  - Data protection and encryption
  - Network security with VPC

- **Observability Best Practices**: `references/observability-best-practices.md`
  - Three pillars: metrics, logs, traces
  - Structured logging with Lambda Powertools
  - X-Ray distributed tracing
  - CloudWatch alarms and dashboards

- **Performance Optimization**: `references/performance-optimization.md`
  - Cold start optimization techniques
  - Memory and CPU optimization
  - Package size reduction
  - Provisioned concurrency patterns

- **Deployment Best Practices**: `references/deployment-best-practices.md`
  - CI/CD pipeline design
  - Testing strategies (unit, integration, load)
  - Deployment strategies (canary, blue/green)
  - Rollback and safety mechanisms

**External Resources**:
- **AWS Well-Architected Serverless Lens**: https://docs.aws.amazon.com/wellarchitected/latest/serverless-applications-lens/
- **ServerlessLand.com**: Pre-built serverless patterns
- **AWS Serverless Workshops**: https://serverlessland.com/learn?type=Workshops

For detailed implementation patterns, anti-patterns, and code examples, refer to the comprehensive references in the skill directory.

## Limitations

- Use this skill only when the task clearly matches its upstream source and local project context.
- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.


---
name: aws-skills
description: "AWS development with infrastructure automation and cloud architecture patterns"
risk: safe
source: "https://github.com/zxkane/aws-skills"
date_added: "2026-02-27"
---

# Aws Skills

## Overview

AWS development with infrastructure automation and cloud architecture patterns

## When to Use This Skill

Use this skill when you need to work with aws development with infrastructure automation and cloud architecture patterns.

## Instructions

This skill provides guidance and patterns for aws development with infrastructure automation and cloud architecture patterns.

For more information, see the [source repository](https://github.com/zxkane/aws-skills).

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: aws-sst-development
description: SST v4 (Ion) expert for managing AWS resources as code with the Pulumi-backed framework. Use when writing or editing sst.config.ts, building infra/ modules (sst.aws.Function/Bucket/Dynamo/Cron/Service/Router, sst.Secret, sst.Linkable, raw aws.* Pulumi resources), wiring resource links,...
risk: critical
source: https://github.com/zxkane/aws-skills/tree/main/plugins/aws-iac/skills/aws-sst-development
source_repo: zxkane/aws-skills
source_type: community
date_added: 2026-07-01
license: MIT
license_source: https://github.com/zxkane/aws-skills/blob/main/LICENSE
---

# SST v4 for AWS
## When to Use

Use this skill when you need sST v4 (Ion) expert for managing AWS resources as code with the Pulumi-backed framework. Use when writing or editing sst.config.ts, building infra/ modules (sst.aws.Function/Bucket/Dynamo/Cron/Service/Router, sst.Secret, sst.Linkable, raw aws.* Pulumi resources), wiring resource links,...

SST v4 (the "Ion" engine) is a Pulumi-backed IaC framework: you describe AWS
resources in TypeScript and SST/Pulumi reconciles them into your account. It
gives you high-level `sst.aws.*` components (Function, Bucket, Dynamo, Cron,
Service, …) that expand into many underlying resources, plus an escape hatch to
*any* raw Pulumi `aws.*` resource for the long tail. This skill encodes a
production-proven way to author, link, test, deploy, and troubleshoot SST
stacks on AWS — distilled from real multi-stack projects that have paid for
each lesson with a prod incident.

**SST and Pulumi are third-party — verify current syntax with Context7**
(`resolve-library-id` → `query-docs` for `sst` or `pulumi-aws`) when you're
unsure about a component's options. Verify AWS-side facts (service limits,
model IDs, IAM action names, region availability) with the AWS docs MCP, never
from memory. The patterns here are the *how*; the docs are the *what*.

## When you're invoked

Figure out which mode you're in and jump to the right reference:

| Situation | Go to |
|-----------|-------|
| New project, or adding a resource/module to an existing SST app | **Author** → `references/authoring.md` |
| Wiring one module's output into another (links, SSM, IAM scope) | **Author** → `references/authoring.md` § Sharing |
| Writing tests for infra so changes don't silently break | **Test** → `references/testing.md` |
| Running a deploy, or a deploy just failed | **Deploy/Operate** → `references/deploy-and-troubleshoot.md` |
| Migrating a resource between Pulumi types, renaming a physical name | **Deploy/Operate** → `references/deploy-and-troubleshoot.md` § Migrations |

Always read the relevant reference before editing — they carry the *why* behind
each rule, which matters more than the rule itself.

## Orientation: read the repo before you touch it

SST projects are conventional but not identical. Before editing, build a quick
map so your change matches the house style instead of fighting it:

1. **`sst.config.ts`** — the app name, `home`, providers/region, `defaultTags`,
   any global `$transform` (Node runtime pin, bundle fixups), and the order in
   which `run()` imports `infra/` modules. The import order *is* the dependency
   order; respect it.
2. **`infra/`** — one file per domain (storage, functions, api, observability…).
   This is where resources are declared. Check for an `infra/CLAUDE.md` — these
   projects keep IaC-specific rules there, and it's the single most valuable
   file to read first.
3. **`infra/tests/`** — source-level Vitest assertions that pin resource
   invariants. If they exist, your change must keep them green and probably
   needs a new assertion.
4. **`package.json` / `.nvmrc`** — package manager (npm vs pnpm), Node version,
   and the `sst`/`pulumi` versions actually installed.

Run `npx sst version` to confirm you're on v4/Ion (the `$config` + `.sst/platform/`
signature). v2/v3 ("SST Classic", CDK-based) is a different framework — these
patterns don't apply there.

## The conventions, and which are universal vs tunable

The projects this skill is built from share a deliberate house style. Some of it
is **universal** (true for any SST v4 + AWS project — apply it everywhere); some
is **project-specific** (a sensible default these projects chose — adopt it for
consistency, but recognize a project may differ).

**Universal — these principles hold for any SST v4 + AWS project:**

- **Control the Node runtime deliberately, in one place.** Don't leave it to
  whatever the installed SST happens to default to. The idiom is a single global
  `$transform(sst.aws.Function, (args) => { args.runtime ??= "nodejs24.x" })` in
  `run()` — `??=` is correct here (the transform runs before the component
  applies its own default, so it fills in only when the user didn't set one).
  Recent SST already defaults to a current Node runtime, so check the installed
  default first (Context7); the transform is then version-independence insurance
  so a future SST downgrade can't silently move your fleet. See
  `references/authoring.md`.
- **Never interpolate a Pulumi `Output<T>` into a plain JS template literal.**
  Use `$interpolate` (or `pulumi.interpolate`). A bare top-level
  `` `${bucket.arn}/*` `` stringifies the `Output` to a `[Output<T>]` placeholder
  and produces a broken ARN that only fails at deploy time (it type-checks and
  `sst dev` runs fine). The fix is `$interpolate``` `${bucket.arn}/*` ``. This
  has caused prod deploy outages. See `references/authoring.md` § Outputs.
- **Migrating a resource between Pulumi *types* should default to two PRs** —
  Pulumi creates-before-destroys, so for a uniqueness-constrained AWS name
  (bucket, IAM role, gateway) the old resource still owns it and the create
  fails with `ConflictException`. Two sequential deploys (teardown, then
  recreate) is the conservative default; `aliases:` / `pulumi import` / state
  surgery can bridge identity in some cases but only with a reviewed plan. See
  `references/deploy-and-troubleshoot.md` § Migrations.
- **Prefer typed `sst.aws.*` / `aws.*` resources over the
  `aws.cloudcontrol.Resource` escape hatch.** CloudControl outputs are
  stringly-typed and `oneOf` fields don't patch cleanly. Use it only when no
  typed resource exists yet, and migrate off it when one ships.

**Project-specific defaults — adopt for consistency, but confirm per repo:**

- **Region `ap-northeast-1`**, `home: "aws"`, and `defaultTags` carrying
  `Project` / `Stage` / `ManagedBy: "sst"`.
- **Stage-gated lifecycle**: `removal: stage === "prod" ? "retain" : "remove"`
  and `protect: stage === "prod"` so prod resources survive a stack tear-down
  and non-prod previews clean up.
- **SSM Parameter Store as the out-of-graph contract** under a
  `/{app}/{stage}/{domain}/...` prefix — for consumers that aren't in the
  Pulumi graph (CI scripts, sibling apps, operators). For *same-app* Lambdas,
  prefer SST `link:` (it wires a real dependency edge and grants IAM); don't
  route same-app sharing through SSM. See `references/authoring.md` § Sharing.
- **Lazy `await import("./infra/<module>")` inside `run()`** so `sst dev`
  hot-reload stays light. (For testing, a module export still runs its top-level
  `new sst.aws.*` unless it's wrapped in a factory function — see
  `references/testing.md` for how to test infra.)
- **Source-level Vitest tests** on every infra module — a lightweight,
  house-style regression net asserting on the *source text* (resource names,
  index shapes, IAM scopes). It's a deliberate choice, not an SST limit: Pulumi
  *does* support runtime mocks (`@pulumi/pulumi/runtime`) for behavioral graph
  tests when a module has real logic. Source assertions don't replace a
  preview-deploy + smoke test. See `references/testing.md`.
- **An observability gate**: every new Lambda/queue/schedule gets an alarm and
  structured logging before merge. Whether you enforce this depends on the
  project, but it's cheap insurance. See `references/deploy-and-troubleshoot.md`
  § Observability.

When you introduce a convention, say which bucket it's in ("this is universal"
vs "matching this repo's house style") so the user can override the
project-specific ones deliberately.

## Working rhythm

1. **Orient** (above) — map config, modules, tests, tooling.
2. **Verify syntax** with Context7 / AWS docs MCP if anything is non-obvious.
   Don't guess at a component's option name.
3. **Author** the resource/module following `references/authoring.md`. Match the
   surrounding file's commenting density and naming — these projects comment the
   *why* heavily, and a terse one-liner in a heavily-annotated file reads as a
   regression.
4. **Test** — add or update source-level assertions (`references/testing.md`) and
   run `npx vitest` (or the repo's `test` script). Run `npx sst diff` and/or
   `tsc --noEmit` to catch type and plan errors before deploying.
5. **Deploy/operate** per `references/deploy-and-troubleshoot.md`. Confirm the
   target account with `aws sts get-caller-identity` before any `sst deploy`.
6. **Clean up** any exported state files — they contain account IDs and ARNs and
   must not linger in `/tmp` or chat history.

## What good looks like

- The change is the smallest diff that satisfies the requirement, in the right
  `infra/` module, wired into `run()` in dependency order.
- Every Lambda gets the right runtime via the global transform (you didn't
  hand-set `runtime` unless intentionally diverging — e.g. a Python function).
- Cross-resource references use `link:` (in-graph) and/or `$interpolate`-scoped
  IAM; outputs other tools consume are published to SSM under the stage prefix.
- New infra has a matching source-level test, and the existing suite stays green.
- You confirmed AWS-side facts via the docs MCP and SST/Pulumi syntax via
  Context7 rather than relying on recall.
- Anything irreversible (deploy, `sst remove`, a resource-type migration) was
  flagged to the user with the account it targets, and migrations were planned
  as two PRs, not one.

## Limitations

- Use this skill only when the task clearly matches its upstream source and local project context.
- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.


---
name: awt-e2e-testing
description: "AI-powered E2E web testing — eyes and hands for AI coding tools. Declarative YAML scenarios, Playwright execution, visual matching (OpenCV + OCR), platform auto-detection (Flutter/React/Vue), learning DB. Install: npx skills add ksgisang/awt-skill --skill awt -g"
risk: critical
source: "https://github.com/ksgisang/awt-skill"
---

# AWT — AI-Powered E2E Testing (Beta)

> `npx skills add ksgisang/awt-skill --skill awt -g`

AWT gives AI coding tools the ability to see and interact with web applications through a real browser. Your AI designs YAML test scenarios; AWT executes them with Playwright.

## When to Use
- You need AI-assisted end-to-end testing through a real browser with declarative YAML scenarios.
- The test flow depends on visual matching, OCR, or platform auto-detection instead of stable DOM selectors.
- You want an E2E toolchain that can both execute tests and explain failures for AI coding workflows.

## What works now
- YAML scenarios → Playwright with human-like interaction
- Visual matching: OpenCV template + OCR (no CSS selectors needed)
- Platform auto-detection: Flutter, React, Next.js, Vue, Angular, Svelte
- Structured failure diagnosis with investigation checklists
- Learning DB: failure→fix patterns in SQLite
- 5 AI providers: Claude, OpenAI, Gemini, DeepSeek, Ollama
- Skill Mode: no extra AI API key needed

## Links
- Main repo: https://github.com/ksgisang/AI-Watch-Tester
- Skill repo: https://github.com/ksgisang/awt-skill
- Cloud demo: https://ai-watch-tester.vercel.app

Built with the help of AI coding tools — and designed to help AI coding tools test better.

Actively developed by a solo developer at AILoopLab. Feedback welcome!

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: ax-extract-workflow
description: "Reconstruct workflow behind a past coding-agent artifact using local ax sessions/commits/skills/tool traces. Use when asked how X was built."
category: development
risk: safe
source: community
source_repo: Necmttn/ax
source_type: community
date_added: "2026-06-21"
author: Necmttn
tags: [ai-coding, workflow-reconstruction, session-analysis, observability]
tools: [claude, cursor, gemini, codex-cli]
license: "AGPL-3.0-only"
license_source: "https://github.com/Necmttn/ax/blob/main/LICENSE"
---

# ax Extract Workflow

## Overview

Use this skill to reconstruct the workflow behind a past coding-agent artifact:
a shipped feature, PR, demo, refactor, report, or other concrete result. It uses
the local `ax` graph to connect commits, sessions, turns, skills, and tool traces
into a short "how this got made" narrative.

`ax` must be installed, available on `PATH`, and able to reach its local database.
If ax cannot connect to its DB, report the connection failure and stop instead of
guessing from memory.

## When to Use This Skill

- Use when the user asks "how did we build X?", "what made X work?", or "extract the workflow behind this artifact."
- Use when the anchor is a commit SHA, date, feature name, PR, session, or repo-local artifact.
- Use when the user wants the sequence of agent skills, prompts, commands, decisions, and checks that led to a result.
- Do not use for a generic activity summary; use normal session listing instead.

## How It Works

### Step 1: Resolve the Anchor

Identify the best anchor from the user's request:

- Commit SHA: use it directly.
- Date or date range: inspect sessions around the date.
- Topic, feature, or artifact name: search recall for related turns, commits, and skills.
- "This repo recently": list recent sessions for the current repo.

```bash
ax recall "live ingest dashboard" --sources=turn,commit,skill --scope=here
ax sessions near abc1234 --json
ax sessions around 2026-06-15 --days=3 --json
ax sessions here --days=14
```

These commands are read-only inspection commands.

### Step 2: Pick Relevant Sessions

Choose the few sessions most likely to explain the artifact. Prefer sessions
that mention the artifact, touch related files, include relevant commits, or have
skills and tool calls that match the work.

If several candidates are plausible, show the user the candidates and ask which
one to inspect.

### Step 3: Inspect the Session Trail

Open each selected session and look for:

- skills used and their order
- user steering points and clarified constraints
- files, tests, and commands that changed the direction of the work
- subagent or tool traces that produced key evidence
- verification steps before the result was considered done

```bash
ax sessions show <session-id> --json
ax sessions show <session-id> --by-role
ax recall "specific keyword from the artifact" --sources=turn,commit --scope=here
```

### Step 4: Write the Reconstruction

Return the result inline unless the user asks for a file. Keep it short and
evidence-grounded:

1. Anchor: the date, commit, feature, or artifact you resolved.
2. Ordered workflow: 4-8 steps showing the skill or action and what it produced.
3. Key decisions: the user or agent choices that changed the path.
4. Verification: tests, reviews, checks, or manual evidence.
5. Reproducer brief: the compact recipe for doing similar work again.

Use session IDs, commit SHAs, and file paths as citations when available.

## Examples

### Reconstruct a Feature from a Commit

```bash
ax sessions near 8f31c2a --json
ax sessions show <session-id> --by-role
ax sessions show <session-id> --json
```

Output shape:

```text
Anchor: 8f31c2a, live ingest dashboard

Workflow:
1. Problem framing -> narrowed the failure to stale dashboard polling.
2. Session recall -> found the earlier ingest-stream design and constraints.
3. Implementation -> wired the server event bus and browser subscription.
4. Verification -> ran typecheck and refreshed the dashboard locally.

Reproducer brief:
Start from the failing artifact, find nearby sessions, inspect role-grouped
skills, then summarize the smallest ordered path from framing to verification.
```

### Reconstruct Work Around a Date

```bash
ax sessions around 2026-06-15 --days=2 --json
ax recall "otel receiver" --sources=turn,commit,skill --scope=here
```

Use this when the user remembers when the work happened but not the commit.

## Best Practices

- Start from the most concrete anchor available: SHA beats date, date beats vague topic.
- Treat ax as the source of truth; do not invent missing skills, costs, commands, or decisions.
- Quote sparingly and only when a user decision or command matters to the reconstruction.
- Keep private transcript details private; summarize rather than dumping logs.
- Separate "what happened" from "what to repeat next time."

## Limitations

- Requires a working local ax installation and reachable local ax database.
- Only sees sessions, commits, skills, and tool traces that ax has ingested.
- Session data can be incomplete when an agent provider omits tool output, cost, or reasoning data.
- It reconstructs workflow, not correctness; still inspect the code and run project checks when making engineering decisions.

## Security & Safety Notes

- Do not upload private transcripts, session logs, prompts, tool outputs, or local database exports.
- Redact secrets, tokens, customer data, file contents, and private conversation text from summaries.
- Use read-only ax inspection commands unless the user explicitly asks for a separate maintenance action.
- Do not run commands that mutate `.ax/`, regenerate indexes, publish reports, or alter repositories as part of reconstruction.

## Related Skills

- `@agenttrace-session-audit` - Use for local agent-session health, cost, latency, and tool-failure audits.
- `@domain-modeling` - Use when the reconstruction reveals terminology or architectural decisions that should be captured.
- `@planning-with-files` - Use when the user wants to turn the reconstructed recipe into a new plan with tracked notes.


---
name: axiom
description: "First-principles assumption auditor. Classifies each hidden assumption (fact / convention / belief / interest-driven), ranks by fragility × impact, and rebuilds conclusions from verified premises. Bilingual: auto-detects Chinese or English."
risk: safe
source: community
date_added: "2026-04-13"
---

# Axiom — First-Principles Assumption Auditor / 第一性原理拆解器

Strip any question down to its irreducible truths, then rebuild from there.
This is not framework fill-in-the-blank — it is assumption prosecution.

把任何问题强制剥离到"不可再拆的最小真相单元"，再从那里重建。
不是框架填空，是假设审判。

## Language Rule / 语言规则

> **Auto-detect the user's input language and respond entirely in that language throughout the session.**
> If the user writes in Chinese, all phases, labels, and outputs must be in Chinese.
> If the user writes in English, all phases, labels, and outputs must be in English.
> Do NOT mix languages unless the user explicitly switches.

---

## When to Use This Skill / 何时使用

- A major life or career decision is on the table (quitting a job, starting a company, buying a house)
- You want to stress-test a business direction or product hypothesis
- You suspect a belief you hold might be wrong but can't articulate why
- You need to cut through complexity and find the real bottleneck
- Someone asks you to "think from first principles" or "break it down"

**Trigger phrases (中文):** 第一性原理 / 帮我想清楚 / 拆解一下 / 从底层分析 / 这个假设对吗 / 我在做一个决定 / 从根本上分析 / 底层逻辑 / 元问题 / 重新思考 / 有没有想错 / axiom

**Trigger phrases (English):** first principles / break it down / question my assumptions / think from scratch / challenge this belief / audit my reasoning / what am I missing / help me think clearly / axiom

---

## What This Skill Does / 核心能力

1. **Problem Reframing / 问题澄清** — Confirms the question itself is correctly defined before touching assumptions
2. **Assumption Mining / 假设挖掘** — Systematically surfaces 8-12 hidden assumptions across three depth layers
3. **Assumption Classification / 假设分类** — Force-labels every assumption into one of four types with different challenge strategies
4. **Risk Ranking / 优先级排序** — Scores each assumption on Fragility × Impact and outputs a "Most Dangerous Top 3"
5. **Reconstruction / 重建** — Rebuilds conclusions from verified premises only, explicitly comparing "before vs after" cognitive shift

---

## The 5-Phase Process / 拆解流程 — 5 阶段

### Phase 1: Problem Reframing — What are you REALLY trying to solve?

**阶段1：问题澄清 — 你真正想解决的是什么？**

Do NOT start decomposing assumptions yet. First confirm the problem itself is correctly defined.

Many people ask "Should I quit my job?" when the real question is "Why can't I grow in my current role?" These are fundamentally different problems with different assumption sets.

**Ask:**
- Who defined this problem? You, someone else's expectations, or a social narrative?
- Is this the root problem, or a symptom of something deeper?
- Restate the core question in one sentence.

**Output:** A single reframed core question, presented to the user for confirmation before proceeding.

> 先不拆假设，先确认问题本身没有被误定义。
> 很多人问"我该不该换工作"，但真正的问题是"我在当前工作里能不能成长"。
> Axiom 先问：这个问题是谁定义的？是你自己、他人期待、还是社会叙事？
> **输出：一句重新表述的核心问题，供用户确认。**

---

### Phase 2: Assumption Mining — What are you believing without proof?

**阶段2：假设挖掘 — 你在相信什么？**

Systematically mine hidden assumptions in three layers:

| Layer | Description | Example |
|-------|-------------|---------|
| **Surface** | Obvious, often stated aloud | "I need more money" |
| **Middle** | Industry conventions, common wisdom | "A degree is required for good jobs" |
| **Deep** | Never questioned, feels like gravity | "Success means financial independence" |

**Goal:** Find 8-12 assumptions. The more concrete, the better. Reject vague statements like "I think this is right" — force specificity.

**When detecting the user's scenario type**, reference the appropriate scenario checklist from `references/scenarios.md` to ensure thorough mining.

> 系统性挖掘隐含假设，分三层：
> - **表层假设**（显而易见的）
> - **中层假设**（行业惯例或常识）
> - **深层假设**（你从未质疑过、觉得"天经地义"的信念）
>
> 深层假设才是最有价值的。
> **目标：找到 8-12 个假设，越具体越好，不接受模糊的"我以为这样更好"。**

---

### Phase 3: Assumption Classification — What is the nature of this belief?

**阶段3：假设分类 — 这个信念的本质是什么？**

Label every assumption with one of four types. Each type has a fundamentally different challenge strategy:

| Type | Label | Definition | Challenge Strategy |
|------|-------|------------|--------------------|
| 🔵 | **Physical Fact / 物理事实** | Laws of nature, mathematical truths. Cannot be changed. | Accept it. Do not waste energy questioning gravity. |
| 🟡 | **Historical Convention / 历史惯例** | Once valid, widely practiced. | Check if the environment has changed. What was true in 2010 may not be true now. |
| 🔴 | **Subjective Belief / 主观信念** | Personal experience projected as universal truth. | Who told you this? Have you personally verified it? Seek counter-evidence. |
| ⚫ | **Interest-Driven / 利益驱动** | Someone benefits from you believing this. | Trace the incentive chain. Who profits from this narrative? |

**The classification itself is the insight.** Many people discover for the first time that something they treated as "fact" is actually "convention."

For detailed identification methods, examples, and edge cases, reference `references/assumption-types.md`.

> 对每个假设打标签。不同性质的假设有不同的质疑方式，处理策略也不同。
> **分类本身就是洞见** — 很多人第一次发现某个"事实"其实是"惯例"。

---

### Phase 4: Risk Ranking — Which assumptions to investigate first?

**阶段4：优先级排序 — 先查哪个？**

Score every assumption on two dimensions:

**Fragility / 脆弱性 (1-5):** How easily can this assumption be disproven?
- 1 = Nearly impossible to overturn (e.g., physical laws)
- 5 = Extremely easy to disprove (e.g., untested market intuition, personal feeling)

**Impact / 影响力 (1-5):** If this assumption is wrong, how much does your conclusion collapse?
- 1 = Barely affects the final conclusion
- 5 = Foundational pillar — if wrong, everything falls apart

```
Risk Score = Fragility × Impact

Output: Top 3 assumptions with highest risk scores, as priority investigation targets.
Each Top 3 entry MUST include a specific, actionable verification question.
```

> 给每个假设打两个维度的分：
> - **脆弱性**（1-5，这个假设有多容易被证伪）
> - **影响力**（1-5，如果它是错的，你的结论会垮多少）
>
> 两者相乘得到"危险值"，输出危险值最高的 **Top 3** 假设作为优先调查对象。
> **这是现有竞品全部缺失的功能。**

---

### Phase 5: Reconstruction — Rebuild from verified ground truth

**阶段5：重建 — 从真相出发，你会怎么做？**

Keep ONLY the assumptions that survived scrutiny. Rebuild the conclusion from scratch using only verified premises.

**Critical requirements:**
- Explicitly compare "Original Thinking" vs "Rebuilt Thinking" side by side
- If the rebuilt conclusion is identical to the original, explain WHY — the analysis must demonstrate that either a genuine shift occurred, or provide specific reasons why the original reasoning was already sound
- Highlight the cognitive shift so the user can see what changed and why

**If the user doesn't have time for a full reconstruction:**
Output the single most important thing to verify: "你最该验证的一件事" / "The one thing you should verify first."

> 只保留被验证的真实前提，从零重建结论。
> **重要的是：新结论必须和原来的直觉有所不同** — 如果完全一样，说明拆解不够深。
> Axiom 会主动对比"原来的想法"和"重建后的想法"，让用户看到认知位移。
>
> 如果用户没有时间做完整重建，至少输出"你最该验证的一件事"。

---

## Anti-Sycophancy Rules / 反谄媚核心规则

These rules are **hard constraints** — they override all other behavioral tendencies. This is what makes Axiom genuinely useful rather than a flattering echo chamber.

| Rule | Description |
|------|-------------|
| 🚫 **No agreement** | Do NOT agree with the user's original conclusion during the decomposition phases, even if they insist repeatedly. |
| 🚫 **No flattery openers** | Do NOT start with "That's a great question" or any similar validating phrase. Get straight to work. |
| 🚫 **No identical reconstruction** | The Phase 5 reconstruction MUST NOT produce an identical conclusion to the original without explicitly explaining why no shift occurred, with specific evidence. |
| ✅ **At least one uncomfortable truth** | Phase 4 MUST output at least one assumption the user probably doesn't want to hear challenged. |
| ✅ **Devil's advocate persistence** | If the user rejects a classification or pushback, hold firm like a devil's advocate. Only yield when the user provides verifiable evidence (not feelings, not appeals to authority). |

> 这是让 axiom 真正有用的关键。Claude 天生倾向于认同用户，必须写入明确规则对抗这个倾向：
> - 🚫 禁止在拆解阶段认同用户的原始结论
> - 🚫 禁止用"这是个好问题"或类似话语开头
> - 🚫 禁止重建阶段给出和原始想法完全一致的结论
> - ✅ 必须在阶段4输出至少一个用户可能不喜欢听的"危险假设"
> - ✅ 必须像 devil's advocate 一样坚持，直到用户提供真实证据

---

## Scenario Reference / 场景引用

When the user's question matches one of these scenario types, reference the corresponding assumption mining checklist from `references/scenarios.md`:

| # | 中文场景 | English Scenario |
|---|---------|-----------------|
| 1 | 职业决策（换工作、创业方向） | Career Decisions (job change, career pivot) |
| 2 | 产品方向验证（创业、新功能） | Business & Product Validation |
| 3 | 消费选择（买房、投资、重大消费） | Financial & Life Decisions |
| 4 | 认知信念质疑（人生观、方法论） | Belief & Worldview Audit |

Each scenario contains 10-15 "high-frequency hidden assumptions" specific to that domain and culture, plus tailored probing questions.

---

## Quick Output Mode / 快捷输出

If the user explicitly requests a quick analysis or is short on time:
- Skip the full 5-phase walkthrough
- Output directly: the **Top 3 most dangerous assumptions** with risk scores and one actionable verification question each
- End with: "你最该验证的一件事是…" / "The single most important thing to verify is…"

---

## Example / 示例

### Chinese Example / 中文示例
See `examples/walkthrough-zh.md` for a complete 5-phase walkthrough using: "我觉得我应该辞职去创业"

### English Example
See `examples/walkthrough-en.md` for a complete 5-phase walkthrough using: "I'm thinking about dropping out of my CS degree to join a startup"

---

## Tips / 使用建议

- The deeper the assumption layer you can reach, the more valuable the analysis
- Don't accept "I just feel it" as evidence — push for specifics
- The most powerful insight often comes from reclassifying what you thought was a "fact" as a "convention"
- Use the Risk Matrix to focus your limited verification energy on what matters most
- If reconstruction matches the original conclusion exactly, the decomposition wasn't deep enough

---

## Common Use Cases / 常见场景

- Major career decisions (quit, pivot, negotiate)
- Startup idea validation before investing time/money
- Challenging "obvious" beliefs that might be holding you back
- Pre-mortem analysis on important life choices
- Auditing investment or financial decisions
- Breaking through analysis paralysis by identifying what actually matters

---

## Related Resources / 参考文件

- `references/scenarios.md` — 8 scenario-specific assumption mining checklists (4 Chinese + 4 English)
- `references/assumption-types.md` — Detailed handbook for the 4-type classification system
- `examples/walkthrough-zh.md` — Complete Chinese example (辞职创业)
- `examples/walkthrough-en.md` — Complete English example (dropping out for startup)

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azd-deployment
description: "Deploy containerized frontend + backend applications to Azure Container Apps with remote builds, managed identity, and idempotent infrastructure."
risk: critical
source: community
date_added: "2026-02-27"
---

# Azure Developer CLI (azd) Container Apps Deployment

Deploy containerized frontend + backend applications to Azure Container Apps with remote builds, managed identity, and idempotent infrastructure.

## Quick Start

```bash
# Initialize and deploy
azd auth login
azd init                    # Creates azure.yaml and .azure/ folder
azd env new <env-name>      # Create environment (dev, staging, prod)
azd up                      # Provision infra + build + deploy
```

## Core File Structure

```
project/
├── azure.yaml              # azd service definitions + hooks
├── infra/
│   ├── main.bicep          # Root infrastructure module
│   ├── main.parameters.json # Parameter injection from env vars
│   └── modules/
│       ├── container-apps-environment.bicep
│       └── container-app.bicep
├── .azure/
│   ├── config.json         # Default environment pointer
│   └── <env-name>/
│       ├── .env            # Environment-specific values (azd-managed)
│       └── config.json     # Environment metadata
└── src/
    ├── frontend/Dockerfile
    └── backend/Dockerfile
```

## azure.yaml Configuration

### Minimal Configuration

```yaml
name: azd-deployment
services:
  backend:
    project: ./src/backend
    language: python
    host: containerapp
    docker:
      path: ./Dockerfile
      remoteBuild: true
```

### Full Configuration with Hooks

```yaml
name: azd-deployment
metadata:
  template: my-project@1.0.0

infra:
  provider: bicep
  path: ./infra

azure:
  location: eastus2

services:
  frontend:
    project: ./src/frontend
    language: ts
    host: containerapp
    docker:
      path: ./Dockerfile
      context: .
      remoteBuild: true

  backend:
    project: ./src/backend
    language: python
    host: containerapp
    docker:
      path: ./Dockerfile
      context: .
      remoteBuild: true

hooks:
  preprovision:
    shell: sh
    run: |
      echo "Before provisioning..."

  postprovision:
    shell: sh
    run: |
      echo "After provisioning - set up RBAC, etc."

  postdeploy:
    shell: sh
    run: |
      echo "Frontend: ${SERVICE_FRONTEND_URI}"
      echo "Backend: ${SERVICE_BACKEND_URI}"
```

### Key azure.yaml Options

| Option | Description |
|--------|-------------|
| `remoteBuild: true` | Build images in Azure Container Registry (recommended) |
| `context: .` | Docker build context relative to project path |
| `host: containerapp` | Deploy to Azure Container Apps |
| `infra.provider: bicep` | Use Bicep for infrastructure |

## Environment Variables Flow

### Three-Level Configuration

1. **Local `.env`** - For local development only
2. **`.azure/<env>/.env`** - azd-managed, auto-populated from Bicep outputs
3. **`main.parameters.json`** - Maps env vars to Bicep parameters

### Parameter Injection Pattern

```json
// infra/main.parameters.json
{
  "parameters": {
    "environmentName": { "value": "${AZURE_ENV_NAME}" },
    "location": { "value": "${AZURE_LOCATION=eastus2}" },
    "azureOpenAiEndpoint": { "value": "${AZURE_OPENAI_ENDPOINT}" }
  }
}
```

Syntax: `${VAR_NAME}` or `${VAR_NAME=default_value}`

### Setting Environment Variables

```bash
# Set for current environment
azd env set AZURE_OPENAI_ENDPOINT "https://my-openai.openai.azure.com"
azd env set AZURE_SEARCH_ENDPOINT "https://my-search.search.windows.net"

# Set during init
azd env new prod
azd env set AZURE_OPENAI_ENDPOINT "..."
```

### Bicep Output → Environment Variable

```bicep
// In main.bicep - outputs auto-populate .azure/<env>/.env
output SERVICE_FRONTEND_URI string = frontend.outputs.uri
output SERVICE_BACKEND_URI string = backend.outputs.uri
output BACKEND_PRINCIPAL_ID string = backend.outputs.principalId
```

## Idempotent Deployments

### Why azd up is Idempotent

1. **Bicep is declarative** - Resources reconcile to desired state
2. **Remote builds tag uniquely** - Image tags include deployment timestamp
3. **ACR reuses layers** - Only changed layers upload

### Preserving Manual Changes

Custom domains added via Portal can be lost on redeploy. Preserve with hooks:

```yaml
hooks:
  preprovision:
    shell: sh
    run: |
      # Save custom domains before provision
      if az containerapp show --name "$FRONTEND_NAME" -g "$RG" &>/dev/null; then
        az containerapp show --name "$FRONTEND_NAME" -g "$RG" \
          --query "properties.configuration.ingress.customDomains" \
          -o json > /tmp/domains.json
      fi

  postprovision:
    shell: sh
    run: |
      # Verify/restore custom domains
      if [ -f /tmp/domains.json ]; then
        echo "Saved domains: $(cat /tmp/domains.json)"
      fi
```

### Handling Existing Resources

```bicep
// Reference existing ACR (don't recreate)
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = {
  name: containerRegistryName
}

// Set customDomains to null to preserve Portal-added domains
customDomains: empty(customDomainsParam) ? null : customDomainsParam
```

## Container App Service Discovery

Internal HTTP routing between Container Apps in same environment:

```bicep
// Backend reference in frontend env vars
env: [
  {
    name: 'BACKEND_URL'
    value: 'http://ca-backend-${resourceToken}'  // Internal DNS
  }
]
```

Frontend nginx proxies to internal URL:
```nginx
location /api {
    proxy_pass $BACKEND_URL;
}
```

## Managed Identity & RBAC

### Enable System-Assigned Identity

```bicep
resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
  identity: {
    type: 'SystemAssigned'
  }
}

output principalId string = containerApp.identity.principalId
```

### Post-Provision RBAC Assignment

```yaml
hooks:
  postprovision:
    shell: sh
    run: |
      PRINCIPAL_ID="${BACKEND_PRINCIPAL_ID}"

      # Azure OpenAI access
      az role assignment create \
        --assignee-object-id "$PRINCIPAL_ID" \
        --assignee-principal-type ServicePrincipal \
        --role "Cognitive Services OpenAI User" \
        --scope "$OPENAI_RESOURCE_ID" 2>/dev/null || true

      # Azure AI Search access
      az role assignment create \
        --assignee-object-id "$PRINCIPAL_ID" \
        --role "Search Index Data Reader" \
        --scope "$SEARCH_RESOURCE_ID" 2>/dev/null || true
```

## Common Commands

```bash
# Environment management
azd env list                        # List environments
azd env select <name>               # Switch environment
azd env get-values                  # Show all env vars
azd env set KEY value               # Set variable

# Deployment
azd up                              # Full provision + deploy
azd provision                       # Infrastructure only
azd deploy                          # Code deployment only
azd deploy --service backend        # Deploy single service

# Debugging
azd show                            # Show project status
az containerapp logs show -n <app> -g <rg> --follow  # Stream logs
```

## Reference Files

- **Bicep patterns**: See references/bicep-patterns.md for Container Apps modules
- **Troubleshooting**: See references/troubleshooting.md for common issues
- **azure.yaml schema**: See references/azure-yaml-schema.md for full options

## Critical Reminders

1. **Always use `remoteBuild: true`** - Local builds fail on M1/ARM Macs deploying to AMD64
2. **Bicep outputs auto-populate .azure/<env>/.env** - Don't manually edit
3. **Use `azd env set` for secrets** - Not main.parameters.json defaults
4. **Service tags (`azd-service-name`)** - Required for azd to find Container Apps
5. **`|| true` in hooks** - Prevent RBAC "already exists" errors from failing deploy

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-agents-persistent-dotnet
description: Azure AI Agents Persistent SDK for .NET. Low-level SDK for creating and managing AI agents with threads, messages, runs, and tools.
risk: critical
source: community
date_added: '2026-02-27'
---

# Azure.AI.Agents.Persistent (.NET)

Low-level SDK for creating and managing persistent AI agents with threads, messages, runs, and tools.

## Installation

```bash
dotnet add package Azure.AI.Agents.Persistent --prerelease
dotnet add package Azure.Identity
```

**Current Versions**: Stable v1.1.0, Preview v1.2.0-beta.8

## Environment Variables

```bash
PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>
MODEL_DEPLOYMENT_NAME=gpt-4o-mini
AZURE_BING_CONNECTION_ID=<bing-connection-resource-id>
AZURE_AI_SEARCH_CONNECTION_ID=<search-connection-resource-id>
```

## Authentication

```csharp
using Azure.AI.Agents.Persistent;
using Azure.Identity;

var projectEndpoint = Environment.GetEnvironmentVariable("PROJECT_ENDPOINT");
PersistentAgentsClient client = new(projectEndpoint, new DefaultAzureCredential());
```

## Client Hierarchy

```
PersistentAgentsClient
├── Administration  → Agent CRUD operations
├── Threads         → Thread management
├── Messages        → Message operations
├── Runs            → Run execution and streaming
├── Files           → File upload/download
└── VectorStores    → Vector store management
```

## Core Workflow

### 1. Create Agent

```csharp
var modelDeploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME");

PersistentAgent agent = await client.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: "Math Tutor",
    instructions: "You are a personal math tutor. Write and run code to answer math questions.",
    tools: [new CodeInterpreterToolDefinition()]
);
```

### 2. Create Thread and Message

```csharp
// Create thread
PersistentAgentThread thread = await client.Threads.CreateThreadAsync();

// Create message
await client.Messages.CreateMessageAsync(
    thread.Id,
    MessageRole.User,
    "I need to solve the equation `3x + 11 = 14`. Can you help me?"
);
```

### 3. Run Agent (Polling)

```csharp
// Create run
ThreadRun run = await client.Runs.CreateRunAsync(
    thread.Id,
    agent.Id,
    additionalInstructions: "Please address the user as Jane Doe."
);

// Poll for completion
do
{
    await Task.Delay(TimeSpan.FromMilliseconds(500));
    run = await client.Runs.GetRunAsync(thread.Id, run.Id);
}
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress);

// Retrieve messages
await foreach (PersistentThreadMessage message in client.Messages.GetMessagesAsync(
    threadId: thread.Id,
    order: ListSortOrder.Ascending))
{
    Console.Write($"{message.Role}: ");
    foreach (MessageContent content in message.ContentItems)
    {
        if (content is MessageTextContent textContent)
            Console.WriteLine(textContent.Text);
    }
}
```

### 4. Streaming Response

```csharp
AsyncCollectionResult<StreamingUpdate> stream = client.Runs.CreateRunStreamingAsync(
    thread.Id,
    agent.Id
);

await foreach (StreamingUpdate update in stream)
{
    if (update.UpdateKind == StreamingUpdateReason.RunCreated)
    {
        Console.WriteLine("--- Run started! ---");
    }
    else if (update is MessageContentUpdate contentUpdate)
    {
        Console.Write(contentUpdate.Text);
    }
    else if (update.UpdateKind == StreamingUpdateReason.RunCompleted)
    {
        Console.WriteLine("\n--- Run completed! ---");
    }
}
```

### 5. Function Calling

```csharp
// Define function tool
FunctionToolDefinition weatherTool = new(
    name: "getCurrentWeather",
    description: "Gets the current weather at a location.",
    parameters: BinaryData.FromObjectAsJson(new
    {
        Type = "object",
        Properties = new
        {
            Location = new { Type = "string", Description = "City and state, e.g. San Francisco, CA" },
            Unit = new { Type = "string", Enum = new[] { "c", "f" } }
        },
        Required = new[] { "location" }
    }, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
);

// Create agent with function
PersistentAgent agent = await client.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: "Weather Bot",
    instructions: "You are a weather bot.",
    tools: [weatherTool]
);

// Handle function calls during polling
do
{
    await Task.Delay(500);
    run = await client.Runs.GetRunAsync(thread.Id, run.Id);

    if (run.Status == RunStatus.RequiresAction
        && run.RequiredAction is SubmitToolOutputsAction submitAction)
    {
        List<ToolOutput> outputs = [];
        foreach (RequiredToolCall toolCall in submitAction.ToolCalls)
        {
            if (toolCall is RequiredFunctionToolCall funcCall)
            {
                // Execute function and get result
                string result = ExecuteFunction(funcCall.Name, funcCall.Arguments);
                outputs.Add(new ToolOutput(toolCall, result));
            }
        }
        run = await client.Runs.SubmitToolOutputsToRunAsync(run, outputs, toolApprovals: null);
    }
}
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress);
```

### 6. File Search with Vector Store

```csharp
// Upload file
PersistentAgentFileInfo file = await client.Files.UploadFileAsync(
    filePath: "document.txt",
    purpose: PersistentAgentFilePurpose.Agents
);

// Create vector store
PersistentAgentsVectorStore vectorStore = await client.VectorStores.CreateVectorStoreAsync(
    fileIds: [file.Id],
    name: "my_vector_store"
);

// Create file search resource
FileSearchToolResource fileSearchResource = new();
fileSearchResource.VectorStoreIds.Add(vectorStore.Id);

// Create agent with file search
PersistentAgent agent = await client.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: "Document Assistant",
    instructions: "You help users find information in documents.",
    tools: [new FileSearchToolDefinition()],
    toolResources: new ToolResources { FileSearch = fileSearchResource }
);
```

### 7. Bing Grounding

```csharp
var bingConnectionId = Environment.GetEnvironmentVariable("AZURE_BING_CONNECTION_ID");

BingGroundingToolDefinition bingTool = new(
    new BingGroundingSearchToolParameters(
        [new BingGroundingSearchConfiguration(bingConnectionId)]
    )
);

PersistentAgent agent = await client.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: "Search Agent",
    instructions: "Use Bing to answer questions about current events.",
    tools: [bingTool]
);
```

### 8. Azure AI Search

```csharp
AzureAISearchToolResource searchResource = new(
    connectionId: searchConnectionId,
    indexName: "my_index",
    topK: 5,
    filter: "category eq 'documentation'",
    queryType: AzureAISearchQueryType.Simple
);

PersistentAgent agent = await client.Administration.CreateAgentAsync(
    model: modelDeploymentName,
    name: "Search Agent",
    instructions: "Search the documentation index to answer questions.",
    tools: [new AzureAISearchToolDefinition()],
    toolResources: new ToolResources { AzureAISearch = searchResource }
);
```

### 9. Cleanup

```csharp
await client.Threads.DeleteThreadAsync(thread.Id);
await client.Administration.DeleteAgentAsync(agent.Id);
await client.VectorStores.DeleteVectorStoreAsync(vectorStore.Id);
await client.Files.DeleteFileAsync(file.Id);
```

## Available Tools

| Tool | Class | Purpose |
|------|-------|---------|
| Code Interpreter | `CodeInterpreterToolDefinition` | Execute Python code, generate visualizations |
| File Search | `FileSearchToolDefinition` | Search uploaded files via vector stores |
| Function Calling | `FunctionToolDefinition` | Call custom functions |
| Bing Grounding | `BingGroundingToolDefinition` | Web search via Bing |
| Azure AI Search | `AzureAISearchToolDefinition` | Search Azure AI Search indexes |
| OpenAPI | `OpenApiToolDefinition` | Call external APIs via OpenAPI spec |
| Azure Functions | `AzureFunctionToolDefinition` | Invoke Azure Functions |
| MCP | `MCPToolDefinition` | Model Context Protocol tools |
| SharePoint | `SharepointToolDefinition` | Access SharePoint content |
| Microsoft Fabric | `MicrosoftFabricToolDefinition` | Access Fabric data |

## Streaming Update Types

| Update Type | Description |
|-------------|-------------|
| `StreamingUpdateReason.RunCreated` | Run started |
| `StreamingUpdateReason.RunInProgress` | Run processing |
| `StreamingUpdateReason.RunCompleted` | Run finished |
| `StreamingUpdateReason.RunFailed` | Run errored |
| `MessageContentUpdate` | Text content chunk |
| `RunStepUpdate` | Step status change |

## Key Types Reference

| Type | Purpose |
|------|---------|
| `PersistentAgentsClient` | Main entry point |
| `PersistentAgent` | Agent with model, instructions, tools |
| `PersistentAgentThread` | Conversation thread |
| `PersistentThreadMessage` | Message in thread |
| `ThreadRun` | Execution of agent against thread |
| `RunStatus` | Queued, InProgress, RequiresAction, Completed, Failed |
| `ToolResources` | Combined tool resources |
| `ToolOutput` | Function call response |

## Best Practices

1. **Always dispose clients** — Use `using` statements or explicit disposal
2. **Poll with appropriate delays** — 500ms recommended between status checks
3. **Clean up resources** — Delete threads and agents when done
4. **Handle all run statuses** — Check for `RequiresAction`, `Failed`, `Cancelled`
5. **Use streaming for real-time UX** — Better user experience than polling
6. **Store IDs not objects** — Reference agents/threads by ID
7. **Use async methods** — All operations should be async

## Error Handling

```csharp
using Azure;

try
{
    var agent = await client.Administration.CreateAgentAsync(...);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
    Console.WriteLine("Resource not found");
}
catch (RequestFailedException ex)
{
    Console.WriteLine($"Error: {ex.Status} - {ex.ErrorCode}: {ex.Message}");
}
```

## Related SDKs

| SDK | Purpose | Install |
|-----|---------|---------|
| `Azure.AI.Agents.Persistent` | Low-level agents (this SDK) | `dotnet add package Azure.AI.Agents.Persistent` |
| `Azure.AI.Projects` | High-level project client | `dotnet add package Azure.AI.Projects` |

## Reference Links

| Resource | URL |
|----------|-----|
| NuGet Package | https://www.nuget.org/packages/Azure.AI.Agents.Persistent |
| API Reference | https://learn.microsoft.com/dotnet/api/azure.ai.agents.persistent |
| GitHub Source | https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/ai/Azure.AI.Agents.Persistent |
| Samples | https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/ai/Azure.AI.Agents.Persistent/samples |

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-agents-persistent-java
description: Azure AI Agents Persistent SDK for Java. Low-level SDK for creating and managing AI agents with threads, messages, runs, and tools.
risk: critical
source: community
date_added: '2026-02-27'
---

# Azure AI Agents Persistent SDK for Java

Low-level SDK for creating and managing persistent AI agents with threads, messages, runs, and tools.

## Installation

```xml
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-ai-agents-persistent</artifactId>
    <version>1.0.0-beta.1</version>
</dependency>
```

## Environment Variables

```bash
PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>
MODEL_DEPLOYMENT_NAME=gpt-4o-mini
```

## Authentication

```java
import com.azure.ai.agents.persistent.PersistentAgentsClient;
import com.azure.ai.agents.persistent.PersistentAgentsClientBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;

String endpoint = System.getenv("PROJECT_ENDPOINT");
PersistentAgentsClient client = new PersistentAgentsClientBuilder()
    .endpoint(endpoint)
    .credential(new DefaultAzureCredentialBuilder().build())
    .buildClient();
```

## Key Concepts

The Azure AI Agents Persistent SDK provides a low-level API for managing persistent agents that can be reused across sessions.

### Client Hierarchy

| Client | Purpose |
|--------|---------|
| `PersistentAgentsClient` | Sync client for agent operations |
| `PersistentAgentsAsyncClient` | Async client for agent operations |

## Core Workflow

### 1. Create Agent

```java
// Create agent with tools
PersistentAgent agent = client.createAgent(
    modelDeploymentName,
    "Math Tutor",
    "You are a personal math tutor."
);
```

### 2. Create Thread

```java
PersistentAgentThread thread = client.createThread();
```

### 3. Add Message

```java
client.createMessage(
    thread.getId(),
    MessageRole.USER,
    "I need help with equations."
);
```

### 4. Run Agent

```java
ThreadRun run = client.createRun(thread.getId(), agent.getId());

// Poll for completion
while (run.getStatus() == RunStatus.QUEUED || run.getStatus() == RunStatus.IN_PROGRESS) {
    Thread.sleep(500);
    run = client.getRun(thread.getId(), run.getId());
}
```

### 5. Get Response

```java
PagedIterable<PersistentThreadMessage> messages = client.listMessages(thread.getId());
for (PersistentThreadMessage message : messages) {
    System.out.println(message.getRole() + ": " + message.getContent());
}
```

### 6. Cleanup

```java
client.deleteThread(thread.getId());
client.deleteAgent(agent.getId());
```

## Best Practices

1. **Use DefaultAzureCredential** for production authentication
2. **Poll with appropriate delays** — 500ms recommended between status checks
3. **Clean up resources** — Delete threads and agents when done
4. **Handle all run statuses** — Check for RequiresAction, Failed, Cancelled
5. **Use async client** for better throughput in high-concurrency scenarios

## Error Handling

```java
import com.azure.core.exception.HttpResponseException;

try {
    PersistentAgent agent = client.createAgent(modelName, name, instructions);
} catch (HttpResponseException e) {
    System.err.println("Error: " + e.getResponse().getStatusCode() + " - " + e.getMessage());
}
```

## Reference Links

| Resource | URL |
|----------|-----|
| Maven Package | https://central.sonatype.com/artifact/com.azure/azure-ai-agents-persistent |
| GitHub Source | https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/ai/azure-ai-agents-persistent |

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-anomalydetector-java
description: "Build anomaly detection applications with Azure AI Anomaly Detector SDK for Java. Use when implementing univariate/multivariate anomaly detection, time-series analysis, or AI-powered monitoring."
risk: critical
source: community
date_added: "2026-02-27"
---

# Azure AI Anomaly Detector SDK for Java

Build anomaly detection applications using the Azure AI Anomaly Detector SDK for Java.

## Installation

```xml
<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-ai-anomalydetector</artifactId>
  <version>3.0.0-beta.6</version>
</dependency>
```

## Client Creation

### Sync and Async Clients

```java
import com.azure.ai.anomalydetector.AnomalyDetectorClientBuilder;
import com.azure.ai.anomalydetector.MultivariateClient;
import com.azure.ai.anomalydetector.UnivariateClient;
import com.azure.core.credential.AzureKeyCredential;

String endpoint = System.getenv("AZURE_ANOMALY_DETECTOR_ENDPOINT");
String key = System.getenv("AZURE_ANOMALY_DETECTOR_API_KEY");

// Multivariate client for multiple correlated signals
MultivariateClient multivariateClient = new AnomalyDetectorClientBuilder()
    .credential(new AzureKeyCredential(key))
    .endpoint(endpoint)
    .buildMultivariateClient();

// Univariate client for single variable analysis
UnivariateClient univariateClient = new AnomalyDetectorClientBuilder()
    .credential(new AzureKeyCredential(key))
    .endpoint(endpoint)
    .buildUnivariateClient();
```

### With DefaultAzureCredential

```java
import com.azure.identity.DefaultAzureCredentialBuilder;

MultivariateClient client = new AnomalyDetectorClientBuilder()
    .credential(new DefaultAzureCredentialBuilder().build())
    .endpoint(endpoint)
    .buildMultivariateClient();
```

## Key Concepts

### Univariate Anomaly Detection
- **Batch Detection**: Analyze entire time series at once
- **Streaming Detection**: Real-time detection on latest data point
- **Change Point Detection**: Detect trend changes in time series

### Multivariate Anomaly Detection
- Detect anomalies across 300+ correlated signals
- Uses Graph Attention Network for inter-correlations
- Three-step process: Train → Inference → Results

## Core Patterns

### Univariate Batch Detection

```java
import com.azure.ai.anomalydetector.models.*;
import java.time.OffsetDateTime;
import java.util.List;

List<TimeSeriesPoint> series = List.of(
    new TimeSeriesPoint(OffsetDateTime.parse("2023-01-01T00:00:00Z"), 1.0),
    new TimeSeriesPoint(OffsetDateTime.parse("2023-01-02T00:00:00Z"), 2.5),
    // ... more data points (minimum 12 points required)
);

UnivariateDetectionOptions options = new UnivariateDetectionOptions(series)
    .setGranularity(TimeGranularity.DAILY)
    .setSensitivity(95);

UnivariateEntireDetectionResult result = univariateClient.detectUnivariateEntireSeries(options);

// Check for anomalies
for (int i = 0; i < result.getIsAnomaly().size(); i++) {
    if (result.getIsAnomaly().get(i)) {
        System.out.printf("Anomaly detected at index %d with value %.2f%n",
            i, series.get(i).getValue());
    }
}
```

### Univariate Last Point Detection (Streaming)

```java
UnivariateLastDetectionResult lastResult = univariateClient.detectUnivariateLastPoint(options);

if (lastResult.isAnomaly()) {
    System.out.println("Latest point is an anomaly!");
    System.out.printf("Expected: %.2f, Upper: %.2f, Lower: %.2f%n",
        lastResult.getExpectedValue(),
        lastResult.getUpperMargin(),
        lastResult.getLowerMargin());
}
```

### Change Point Detection

```java
UnivariateChangePointDetectionOptions changeOptions =
    new UnivariateChangePointDetectionOptions(series, TimeGranularity.DAILY);

UnivariateChangePointDetectionResult changeResult =
    univariateClient.detectUnivariateChangePoint(changeOptions);

for (int i = 0; i < changeResult.getIsChangePoint().size(); i++) {
    if (changeResult.getIsChangePoint().get(i)) {
        System.out.printf("Change point at index %d with confidence %.2f%n",
            i, changeResult.getConfidenceScores().get(i));
    }
}
```

### Multivariate Model Training

```java
import com.azure.ai.anomalydetector.models.*;
import com.azure.core.util.polling.SyncPoller;

// Prepare training request with blob storage data
ModelInfo modelInfo = new ModelInfo()
    .setDataSource("https://storage.blob.core.windows.net/container/data.zip?sasToken")
    .setStartTime(OffsetDateTime.parse("2023-01-01T00:00:00Z"))
    .setEndTime(OffsetDateTime.parse("2023-06-01T00:00:00Z"))
    .setSlidingWindow(200)
    .setDisplayName("MyMultivariateModel");

// Train model (long-running operation)
AnomalyDetectionModel trainedModel = multivariateClient.trainMultivariateModel(modelInfo);

String modelId = trainedModel.getModelId();
System.out.println("Model ID: " + modelId);

// Check training status
AnomalyDetectionModel model = multivariateClient.getMultivariateModel(modelId);
System.out.println("Status: " + model.getModelInfo().getStatus());
```

### Multivariate Batch Inference

```java
MultivariateBatchDetectionOptions detectionOptions = new MultivariateBatchDetectionOptions()
    .setDataSource("https://storage.blob.core.windows.net/container/inference-data.zip?sasToken")
    .setStartTime(OffsetDateTime.parse("2023-07-01T00:00:00Z"))
    .setEndTime(OffsetDateTime.parse("2023-07-31T00:00:00Z"))
    .setTopContributorCount(10);

MultivariateDetectionResult detectionResult =
    multivariateClient.detectMultivariateBatchAnomaly(modelId, detectionOptions);

String resultId = detectionResult.getResultId();

// Poll for results
MultivariateDetectionResult result = multivariateClient.getBatchDetectionResult(resultId);
for (AnomalyState state : result.getResults()) {
    if (state.getValue().isAnomaly()) {
        System.out.printf("Anomaly at %s, severity: %.2f%n",
            state.getTimestamp(),
            state.getValue().getSeverity());
    }
}
```

### Multivariate Last Point Detection

```java
MultivariateLastDetectionOptions lastOptions = new MultivariateLastDetectionOptions()
    .setVariables(List.of(
        new VariableValues("variable1", List.of("timestamp1"), List.of(1.0f)),
        new VariableValues("variable2", List.of("timestamp1"), List.of(2.5f))
    ))
    .setTopContributorCount(5);

MultivariateLastDetectionResult lastResult =
    multivariateClient.detectMultivariateLastAnomaly(modelId, lastOptions);

if (lastResult.getValue().isAnomaly()) {
    System.out.println("Anomaly detected!");
    // Check contributing variables
    for (AnomalyContributor contributor : lastResult.getValue().getInterpretation()) {
        System.out.printf("Variable: %s, Contribution: %.2f%n",
            contributor.getVariable(),
            contributor.getContributionScore());
    }
}
```

### Model Management

```java
// List all models
PagedIterable<AnomalyDetectionModel> models = multivariateClient.listMultivariateModels();
for (AnomalyDetectionModel m : models) {
    System.out.printf("Model: %s, Status: %s%n",
        m.getModelId(),
        m.getModelInfo().getStatus());
}

// Delete a model
multivariateClient.deleteMultivariateModel(modelId);
```

## Error Handling

```java
import com.azure.core.exception.HttpResponseException;

try {
    univariateClient.detectUnivariateEntireSeries(options);
} catch (HttpResponseException e) {
    System.out.println("Status code: " + e.getResponse().getStatusCode());
    System.out.println("Error: " + e.getMessage());
}
```

## Environment Variables

```bash
AZURE_ANOMALY_DETECTOR_ENDPOINT=https://<resource>.cognitiveservices.azure.com/
AZURE_ANOMALY_DETECTOR_API_KEY=<your-api-key>
```

## Best Practices

1. **Minimum Data Points**: Univariate requires at least 12 points; more data improves accuracy
2. **Granularity Alignment**: Match `TimeGranularity` to your actual data frequency
3. **Sensitivity Tuning**: Higher values (0-99) detect more anomalies
4. **Multivariate Training**: Use 200-1000 sliding window based on pattern complexity
5. **Error Handling**: Always handle `HttpResponseException` for API errors

## Trigger Phrases

- "anomaly detection Java"
- "detect anomalies time series"
- "multivariate anomaly Java"
- "univariate anomaly detection"
- "streaming anomaly detection"
- "change point detection"
- "Azure AI Anomaly Detector"

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-contentsafety-java
description: "Build content moderation applications using the Azure AI Content Safety SDK for Java."
risk: critical
source: community
date_added: "2026-02-27"
---

# Azure AI Content Safety SDK for Java

Build content moderation applications using the Azure AI Content Safety SDK for Java.

## Installation

```xml
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-ai-contentsafety</artifactId>
    <version>1.1.0-beta.1</version>
</dependency>
```

## Client Creation

### With API Key

```java
import com.azure.ai.contentsafety.ContentSafetyClient;
import com.azure.ai.contentsafety.ContentSafetyClientBuilder;
import com.azure.ai.contentsafety.BlocklistClient;
import com.azure.ai.contentsafety.BlocklistClientBuilder;
import com.azure.core.credential.KeyCredential;

String endpoint = System.getenv("CONTENT_SAFETY_ENDPOINT");
String key = System.getenv("CONTENT_SAFETY_KEY");

ContentSafetyClient contentSafetyClient = new ContentSafetyClientBuilder()
    .credential(new KeyCredential(key))
    .endpoint(endpoint)
    .buildClient();

BlocklistClient blocklistClient = new BlocklistClientBuilder()
    .credential(new KeyCredential(key))
    .endpoint(endpoint)
    .buildClient();
```

### With DefaultAzureCredential

```java
import com.azure.identity.DefaultAzureCredentialBuilder;

ContentSafetyClient client = new ContentSafetyClientBuilder()
    .credential(new DefaultAzureCredentialBuilder().build())
    .endpoint(endpoint)
    .buildClient();
```

## Key Concepts

### Harm Categories
| Category | Description |
|----------|-------------|
| Hate | Discriminatory language based on identity groups |
| Sexual | Sexual content, relationships, acts |
| Violence | Physical harm, weapons, injury |
| Self-harm | Self-injury, suicide-related content |

### Severity Levels
- Text: 0-7 scale (default outputs 0, 2, 4, 6)
- Image: 0, 2, 4, 6 (trimmed scale)

## Core Patterns

### Analyze Text

```java
import com.azure.ai.contentsafety.models.*;

AnalyzeTextResult result = contentSafetyClient.analyzeText(
    new AnalyzeTextOptions("This is text to analyze"));

for (TextCategoriesAnalysis category : result.getCategoriesAnalysis()) {
    System.out.printf("Category: %s, Severity: %d%n",
        category.getCategory(),
        category.getSeverity());
}
```

### Analyze Text with Options

```java
AnalyzeTextOptions options = new AnalyzeTextOptions("Text to analyze")
    .setCategories(Arrays.asList(
        TextCategory.HATE,
        TextCategory.VIOLENCE))
    .setOutputType(AnalyzeTextOutputType.EIGHT_SEVERITY_LEVELS);

AnalyzeTextResult result = contentSafetyClient.analyzeText(options);
```

### Analyze Text with Blocklist

```java
AnalyzeTextOptions options = new AnalyzeTextOptions("I h*te you and want to k*ll you")
    .setBlocklistNames(Arrays.asList("my-blocklist"))
    .setHaltOnBlocklistHit(true);

AnalyzeTextResult result = contentSafetyClient.analyzeText(options);

if (result.getBlocklistsMatch() != null) {
    for (TextBlocklistMatch match : result.getBlocklistsMatch()) {
        System.out.printf("Blocklist: %s, Item: %s, Text: %s%n",
            match.getBlocklistName(),
            match.getBlocklistItemId(),
            match.getBlocklistItemText());
    }
}
```

### Analyze Image

```java
import com.azure.ai.contentsafety.models.*;
import com.azure.core.util.BinaryData;
import java.nio.file.Files;
import java.nio.file.Paths;

// From file
byte[] imageBytes = Files.readAllBytes(Paths.get("image.png"));
ContentSafetyImageData imageData = new ContentSafetyImageData()
    .setContent(BinaryData.fromBytes(imageBytes));

AnalyzeImageResult result = contentSafetyClient.analyzeImage(
    new AnalyzeImageOptions(imageData));

for (ImageCategoriesAnalysis category : result.getCategoriesAnalysis()) {
    System.out.printf("Category: %s, Severity: %d%n",
        category.getCategory(),
        category.getSeverity());
}
```

### Analyze Image from URL

```java
ContentSafetyImageData imageData = new ContentSafetyImageData()
    .setBlobUrl("https://example.com/image.jpg");

AnalyzeImageResult result = contentSafetyClient.analyzeImage(
    new AnalyzeImageOptions(imageData));
```

## Blocklist Management

### Create or Update Blocklist

```java
import com.azure.core.http.rest.RequestOptions;
import com.azure.core.http.rest.Response;
import com.azure.core.util.BinaryData;
import java.util.Map;

Map<String, String> description = Map.of("description", "Custom blocklist");
BinaryData resource = BinaryData.fromObject(description);

Response<BinaryData> response = blocklistClient.createOrUpdateTextBlocklistWithResponse(
    "my-blocklist", resource, new RequestOptions());

if (response.getStatusCode() == 201) {
    System.out.println("Blocklist created");
} else if (response.getStatusCode() == 200) {
    System.out.println("Blocklist updated");
}
```

### Add Block Items

```java
import com.azure.ai.contentsafety.models.*;
import java.util.Arrays;

List<TextBlocklistItem> items = Arrays.asList(
    new TextBlocklistItem("badword1").setDescription("Offensive term"),
    new TextBlocklistItem("badword2").setDescription("Another term")
);

AddOrUpdateTextBlocklistItemsResult result = blocklistClient.addOrUpdateBlocklistItems(
    "my-blocklist",
    new AddOrUpdateTextBlocklistItemsOptions(items));

for (TextBlocklistItem item : result.getBlocklistItems()) {
    System.out.printf("Added: %s (ID: %s)%n",
        item.getText(),
        item.getBlocklistItemId());
}
```

### List Blocklists

```java
PagedIterable<TextBlocklist> blocklists = blocklistClient.listTextBlocklists();

for (TextBlocklist blocklist : blocklists) {
    System.out.printf("Blocklist: %s, Description: %s%n",
        blocklist.getName(),
        blocklist.getDescription());
}
```

### Get Blocklist

```java
TextBlocklist blocklist = blocklistClient.getTextBlocklist("my-blocklist");
System.out.println("Name: " + blocklist.getName());
```

### List Block Items

```java
PagedIterable<TextBlocklistItem> items =
    blocklistClient.listTextBlocklistItems("my-blocklist");

for (TextBlocklistItem item : items) {
    System.out.printf("ID: %s, Text: %s%n",
        item.getBlocklistItemId(),
        item.getText());
}
```

### Remove Block Items

```java
List<String> itemIds = Arrays.asList("item-id-1", "item-id-2");

blocklistClient.removeBlocklistItems(
    "my-blocklist",
    new RemoveTextBlocklistItemsOptions(itemIds));
```

### Delete Blocklist

```java
blocklistClient.deleteTextBlocklist("my-blocklist");
```

## Error Handling

```java
import com.azure.core.exception.HttpResponseException;

try {
    contentSafetyClient.analyzeText(new AnalyzeTextOptions("test"));
} catch (HttpResponseException e) {
    System.out.println("Status: " + e.getResponse().getStatusCode());
    System.out.println("Error: " + e.getMessage());
    // Common codes: InvalidRequestBody, ResourceNotFound, TooManyRequests
}
```

## Environment Variables

```bash
CONTENT_SAFETY_ENDPOINT=https://<resource>.cognitiveservices.azure.com/
CONTENT_SAFETY_KEY=<your-api-key>
```

## Best Practices

1. **Blocklist Delay**: Changes take ~5 minutes to take effect
2. **Category Selection**: Only request needed categories to reduce latency
3. **Severity Thresholds**: Typically block severity >= 4 for strict moderation
4. **Batch Processing**: Process multiple items in parallel for throughput
5. **Caching**: Cache blocklist results where appropriate

## Trigger Phrases

- "content safety Java"
- "content moderation Azure"
- "analyze text safety"
- "image moderation Java"
- "blocklist management"
- "hate speech detection"
- "harmful content filter"

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-contentsafety-py
description: Azure AI Content Safety SDK for Python. Use for detecting harmful content in text and images with multi-severity classification.
risk: critical
source: community
date_added: '2026-02-27'
---

# Azure AI Content Safety SDK for Python

Detect harmful user-generated and AI-generated content in applications.

## Installation

```bash
pip install azure-ai-contentsafety
```

## Environment Variables

```bash
CONTENT_SAFETY_ENDPOINT=https://<resource>.cognitiveservices.azure.com
CONTENT_SAFETY_KEY=<your-api-key>
```

## Authentication

### API Key

```python
from azure.ai.contentsafety import ContentSafetyClient
from azure.core.credentials import AzureKeyCredential
import os

client = ContentSafetyClient(
    endpoint=os.environ["CONTENT_SAFETY_ENDPOINT"],
    credential=AzureKeyCredential(os.environ["CONTENT_SAFETY_KEY"])
)
```

### Entra ID

```python
from azure.ai.contentsafety import ContentSafetyClient
from azure.identity import DefaultAzureCredential

client = ContentSafetyClient(
    endpoint=os.environ["CONTENT_SAFETY_ENDPOINT"],
    credential=DefaultAzureCredential()
)
```

## Analyze Text

```python
from azure.ai.contentsafety import ContentSafetyClient
from azure.ai.contentsafety.models import AnalyzeTextOptions, TextCategory
from azure.core.credentials import AzureKeyCredential

client = ContentSafetyClient(endpoint, AzureKeyCredential(key))

request = AnalyzeTextOptions(text="Your text content to analyze")
response = client.analyze_text(request)

# Check each category
for category in [TextCategory.HATE, TextCategory.SELF_HARM,
                 TextCategory.SEXUAL, TextCategory.VIOLENCE]:
    result = next((r for r in response.categories_analysis
                   if r.category == category), None)
    if result:
        print(f"{category}: severity {result.severity}")
```

## Analyze Image

```python
from azure.ai.contentsafety import ContentSafetyClient
from azure.ai.contentsafety.models import AnalyzeImageOptions, ImageData
from azure.core.credentials import AzureKeyCredential
import base64

client = ContentSafetyClient(endpoint, AzureKeyCredential(key))

# From file
with open("image.jpg", "rb") as f:
    image_data = base64.b64encode(f.read()).decode("utf-8")

request = AnalyzeImageOptions(
    image=ImageData(content=image_data)
)

response = client.analyze_image(request)

for result in response.categories_analysis:
    print(f"{result.category}: severity {result.severity}")
```

### Image from URL

```python
from azure.ai.contentsafety.models import AnalyzeImageOptions, ImageData

request = AnalyzeImageOptions(
    image=ImageData(blob_url="https://example.com/image.jpg")
)

response = client.analyze_image(request)
```

## Text Blocklist Management

### Create Blocklist

```python
from azure.ai.contentsafety import BlocklistClient
from azure.ai.contentsafety.models import TextBlocklist
from azure.core.credentials import AzureKeyCredential

blocklist_client = BlocklistClient(endpoint, AzureKeyCredential(key))

blocklist = TextBlocklist(
    blocklist_name="my-blocklist",
    description="Custom terms to block"
)

result = blocklist_client.create_or_update_text_blocklist(
    blocklist_name="my-blocklist",
    options=blocklist
)
```

### Add Block Items

```python
from azure.ai.contentsafety.models import AddOrUpdateTextBlocklistItemsOptions, TextBlocklistItem

items = AddOrUpdateTextBlocklistItemsOptions(
    blocklist_items=[
        TextBlocklistItem(text="blocked-term-1"),
        TextBlocklistItem(text="blocked-term-2")
    ]
)

result = blocklist_client.add_or_update_blocklist_items(
    blocklist_name="my-blocklist",
    options=items
)
```

### Analyze with Blocklist

```python
from azure.ai.contentsafety.models import AnalyzeTextOptions

request = AnalyzeTextOptions(
    text="Text containing blocked-term-1",
    blocklist_names=["my-blocklist"],
    halt_on_blocklist_hit=True
)

response = client.analyze_text(request)

if response.blocklists_match:
    for match in response.blocklists_match:
        print(f"Blocked: {match.blocklist_item_text}")
```

## Severity Levels

Text analysis returns 4 severity levels (0, 2, 4, 6) by default. For 8 levels (0-7):

```python
from azure.ai.contentsafety.models import AnalyzeTextOptions, AnalyzeTextOutputType

request = AnalyzeTextOptions(
    text="Your text",
    output_type=AnalyzeTextOutputType.EIGHT_SEVERITY_LEVELS
)
```

## Harm Categories

| Category | Description |
|----------|-------------|
| `Hate` | Attacks based on identity (race, religion, gender, etc.) |
| `Sexual` | Sexual content, relationships, anatomy |
| `Violence` | Physical harm, weapons, injury |
| `SelfHarm` | Self-injury, suicide, eating disorders |

## Severity Scale

| Level | Text Range | Image Range | Meaning |
|-------|------------|-------------|---------|
| 0 | Safe | Safe | No harmful content |
| 2 | Low | Low | Mild references |
| 4 | Medium | Medium | Moderate content |
| 6 | High | High | Severe content |

## Client Types

| Client | Purpose |
|--------|---------|
| `ContentSafetyClient` | Analyze text and images |
| `BlocklistClient` | Manage custom blocklists |

## Best Practices

1. **Use blocklists** for domain-specific terms
2. **Set severity thresholds** appropriate for your use case
3. **Handle multiple categories** — content can be harmful in multiple ways
4. **Use halt_on_blocklist_hit** for immediate rejection
5. **Log analysis results** for audit and improvement
6. **Consider 8-severity mode** for finer-grained control
7. **Pre-moderate AI outputs** before showing to users

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.


---
name: azure-ai-contentsafety-ts
description: "Analyze text and images for harmful content with customizable blocklists."
risk: critical
source: community
date_added: "2026-02-27"
---

# Azure AI Content Safety REST SDK for TypeScript

Analyze text and images for harmful content with customizable blocklists.

## Installation

```bash
npm install @azure-rest/ai-content-safety @azure/identity @azure/core-auth
```

## Environment Variables

```bash
CONTENT_SAFETY_ENDPOINT=https://<resource>.cognitiveservices.azure.com
CONTENT_SAFETY_KEY=<api-key>
```

## Authentication

**Important**: This is a REST client. `ContentSafetyClient` is a **function**, not a class.

### API Key

```typescript
import ContentSafetyClient from "@azure-rest/ai-content-safety";
import { AzureKeyCredential } from "@azure/core-auth";

const client = ContentSafetyClient(
  process.env.CONTENT_SAFETY_ENDPOINT!,
  new AzureKeyCredential(process.env.CONTENT_SAFETY_KEY!)
);
```

### DefaultAzureCredential

```typescript
import ContentSafetyClient from "@azure-rest/ai-content-safety";
import { DefaultAzureCredential } from "@azure/identity";

const client = ContentSafetyClient(
  process.env.CONTENT_SAFETY_ENDPOINT!,
  new DefaultAzureCredential()
);
```

## Analyze Text

```typescript
import ContentSafetyClient, { isUnexpected } from "@azure-rest/ai-content-safety";

const result = await client.path("/text:analyze").post({
  body: {
    text: "Text content to analyze",
    categories: ["Hate", "Sexual", "Violence", "SelfHarm"],
    outputType: "FourSeverityLevels"  // or "EightSeverityLevels"
  }
});

if (isUnexpected(result)) {
  throw result.body;
}

for (const analysis of result.body.categoriesAnalysis) {
  console.log(`${analysis.category}: severity ${analysis.severity}`);
}
```

## Analyze Image

### Base64 Content

```typescript
import { readFileSync } from "node:fs";

const imageBuffer = readFileSync("./image.png");
const base64Image = imageBuffer.toString("base64");

const result = await client.path("/image:analyze").post({
  body: {
    image: { content: base64Image }
  }
});

if (isUnexpected(result)) {
  throw result.body;
}

for (const analysis of result.body.categoriesAnalysis) {
  console.log(`${analysis.category}: severity ${analysis.severity}`);
}
```

### Blob URL

```typescript
const result = await client.path("/image:analyze").post({
  body: {
    image: { blobUrl: "https://storage.blob.core.windows.net/container/image.png" }
  }
});
```

## Blocklist Management

### Create Blocklist

```typescript
const result = await client
  .path("/text/blocklists/{blocklistName}", "my-blocklist")
  .patch({
    contentType: "application/merge-patch+json",
    body: {
      description: "Custom blocklist for prohibited terms"
    }
  });

if (isUnexpected(result)) {
  throw result.body;
}

console.log(`Created: ${result.body.blocklistName}`);
```

### Add Items to Blocklist

```typescript
const result = await client
  .path("/text/blocklists/{blocklistName}:addOrUpdateBlocklistItems", "my-blocklist")
  .post({
    body: {
      blocklistItems: [
        { text: "prohibited-term-1", description: "First blocked term" },
        { text: "prohibited-term-2", description: "Second blocked term" }
      ]
    }
  });

if (isUnexpected(result)) {
  throw result.body;
}

for (const item of result.body.blocklistItems ?? []) {
  console.log(`Added: ${item.blocklistItemId}`);
}
```

### Analyze with Blocklist

```typescript
const result = await client.path("/text:analyze").post({
  body: {
    text: "Text that might contain blocked terms",
    blocklistNames: ["my-blocklist"],
    haltOnBlocklistHit: false
  }
});

if (isUnexpected(result)) {
  throw result.body;
}

// Check blocklist matches
if (result.body.blocklistsMatch) {
  for (const match of result.body.blocklistsMatch) {
    console.log(`Blocked: "${match.blocklistItemText}" from ${match.blocklistName}`);
  }
}
```

### List Blocklists

```typescript
const result = await client.path("/text/blocklists").get();

if (isUnexpected(result)) {
  throw result.body;
}

for (const blocklist of result.body.value ?? []) {
  console.log(`${blocklist.blocklistName}: ${blocklist.description}`);
}
```

### Delete Blocklist

```typescript
await client.path("/text/blocklists/{blocklistName}", "my-blocklist").delete();
```

## Harm Categories

| Category | API Term | Description |
|----------|----------|-------------|
| Hate and Fairness | `Hate` | Discriminatory language targeting identity groups |
| Sexual | `Sexual` | Sexual content, nudity, pornography |
| Violence | `Violence` | Physical harm, weapons, terrorism |
| Self-Harm | `SelfHarm` | Self-injury, suicide, eating disorders |

## Severity Levels

| Level | Risk | Recommended Action |
|-------|------|-------------------|
| 0 | Safe | Allow |
| 2 | Low | Review or allow with warning |
| 4 | Medium | Block or require human review |
| 6 | High | Block immediately |

**Output Types**:
- `FourSeverityLevels` (default): Returns 0, 2, 4, 6
- `EightSeverityLevels`: Returns 0-7

## Content Moderation Helper

```typescript
import ContentSafetyClient, {
  isUnexpected,
  TextCategoriesAnalysisOutput
} from "@azure-rest/ai-content-safety";

interface ModerationResult {
  isAllowed: boolean;
  flaggedCategories: string[];
  maxSeverity: number;
  blocklistMatches: string[];
}

async function moderateContent(
  client: ReturnType<typeof ContentSafetyClient>,
  text: string,
  maxAllowedSeverity = 2,
  blocklistNames: string[] = []
): Promise<ModerationResult> {
  const result = await client.path("/text:analyze").post({
    body: { text, blocklistNames, haltOnBlocklistHit: false }
  });

  if (isUnexpected(result)) {
    throw result.body;
  }

  const flaggedCategories = result.body.categoriesAnalysis
    .filter(c => (c.severity ?? 0) > maxAllowedSeverity)
    .map(c => c.category!);

  const maxSeverity = Math.max(
    ...result.body.categoriesAnalysis.map(c => c.severity ?? 0)
  );

  const blocklistMatches = (result.body.blocklistsMatch ?? [])
    .map(m => m.blocklistItemText!);

  return {
    isAllowed: flaggedCategories.length === 0 && blocklistMatches.length === 0,
    flaggedCategories,
    maxSeverity,
    blocklistMatches
  };
}
```

## API Endpoints

| Operation | Method | Path |
|-----------|--------|------|
| Analyze Text | POST | `/text:analyze` |
| Analyze Image | POST | `/image:analyze` |
| Create/Update Blocklist | PATCH | `/text/blocklists/{blocklistName}` |
| List Blocklists | GET | `/text/blocklists` |
| Delete Blocklist | DELETE | `/text/blocklists/{blocklistName}` |
| Add Blocklist Items | POST | `/text/blocklists/{blocklistName}:addOrUpdateBlocklistItems` |
| List Blocklist Items | GET | `/text/blocklists/{blocklistName}/blocklistItems` |
| Remove Blocklist Items | POST | `/text/blocklists/{blocklistName}:removeBlocklistItems` |

## Key Types

```typescript
import ContentSafetyClient, {
  isUnexpected,
  AnalyzeTextParameters,
  AnalyzeImageParameters,
  TextCategoriesAnalysisOutput,
  ImageCategoriesAnalysisOutput,
  TextBlocklist,
  TextBlocklistItem
} from "@azure-rest/ai-content-safety";
```

## Best Practices

1. **Always use isUnexpected()** - Type guard for error handling
2. **Set appropriate thresholds** - Different categories may need different severity thresholds
3. **Use blocklists for domain-specific terms** - Supplement AI detection with custom rules
4. **Log moderation decisions** - Keep audit trail for compliance
5. **Handle edge cases** - Empty text, very long text, unsupported image formats

## When to Use
This skill is applicable to execute the workflow or actions described in the overview.

## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.