Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Message Enrichment

ASecurity

Enrich Protean commands and events with cross-cutting metadata using command enrichers and event enrichers. Enrichers are domain-level functions that return a dict merged into a message's metadata.extensions - useful for tenant ids, request/correlation context, actor info, and audit data that should ride along with every command or event without polluting the payload. Use @domain.command_enricher for commands and @domain.event_enricher for events. Use when you need to attach context to messag...

45 stars
0 votes
0 copies
0 views
Added 9/20/2026
developmentpythongo

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add proteanhq/protean --skill message-enrichment --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Message Enrichment?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Message Enrichment
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/proteanhq-message-enrichment/badge)](https://www.skillsdirectory.com/skills/proteanhq-message-enrichment)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: message-enrichment
description: Enrich Protean commands and events with cross-cutting metadata using command enrichers and event enrichers. Enrichers are domain-level functions that return a dict merged into a message's metadata.extensions - useful for tenant ids, request/correlation context, actor info, and audit data that should ride along with every command or event without polluting the payload. Use @domain.command_enricher for commands and @domain.event_enricher for events. Use when you need to attach context to messages, add metadata to commands or events, inject tenant/request/user info, enrich messages, build an audit trail, or when the user asks to "add a command enricher", "add an event enricher", "enrich commands/events", "attach metadata", or "inject context into messages".
license: Apache-2.0
compatibility: Requires Python 3.11+, protean framework
metadata:
  author: proteanhq
  version: "0.1"
  category: element
---

# Message Enrichment

Enrichers attach cross-cutting context to messages. A **command enricher** runs as a
command is processed; an **event enricher** runs as an aggregate raises an event. Each
returns a `dict` that is merged into the message's `metadata.extensions`, so the data
travels with the message (through serialization and the event store) without bloating
the payload.

## Basic structure

```python
from protean import Domain
from protean.utils.globals import g

domain = Domain()

# Command enricher: receives the command, returns a dict
@domain.command_enricher
def add_request_context(command):
    return {"request_id": getattr(g, "request_id", None)}

# Event enricher: receives the event AND the aggregate, returns a dict
@domain.event_enricher
def add_tenant_context(event, aggregate):
    return {"tenant_id": getattr(g, "tenant_id", None)}
```

## Key rules

1. **Two kinds, two signatures** - Command enricher: `def fn(command) -> dict`. Event enricher: `def fn(event, aggregate) -> dict` (it also gets the aggregate, so it can read aggregate state)
2. **Register with the decorator** - `@domain.command_enricher` / `@domain.event_enricher`. For reusable functions, use `domain.register_command_enricher(fn)` / `domain.register_event_enricher(fn)`
3. **Return a dict (or `None`)** - The returned dict is merged into `metadata.extensions`. Returning `None` or `{}` is a no-op
4. **Enrichers are domain-level** - They are NOT `part_of` an aggregate; they run for every command (or every event) in the domain
5. **Run order is FIFO; later wins** - Enrichers run in registration order; a later enricher can overwrite a key set by an earlier one
6. **Keep them pure and fast** - Read context (e.g. from `g`), return data. Do not mutate the message, load aggregates, or perform I/O
7. **Errors abort the message** - If an enricher raises, the command is not processed / the event is not appended. Use safe access like `getattr(g, "key", None)`
8. **Timing** - Command enrichers run after command metadata is built, before handling; event enrichers run inside `aggregate.raise_()`, before the event is appended (and they also run for fact events)

## Where the data lands

```python
command._metadata.extensions   # after command enrichment
event._metadata.extensions     # after event enrichment
# Downstream, handlers/projectors read it via:
#   g.message_in_context.metadata.extensions
```

## Quick example: tenant + audit context

```python
from protean import Domain
from protean.utils.globals import g

domain = Domain()

@domain.command_enricher
def command_audit(command):
    return {
        "request_id": getattr(g, "request_id", None),
        "actor_id": getattr(g, "actor_id", None),
    }

@domain.event_enricher
def event_audit(event, aggregate):
    return {
        "tenant_id": getattr(g, "tenant_id", None),
        "aggregate_type": type(aggregate).__name__,
    }
```

## Common mistakes

### Wrong signature for an event enricher

```python
@domain.event_enricher
def add_ctx(event):  # Wrong! Event enrichers receive (event, aggregate)
    return {...}
```

Instead: `def add_ctx(event, aggregate): ...`

### Mutating the message instead of returning a dict

```python
@domain.command_enricher
def add_ctx(command):
    command._metadata.extensions["x"] = 1  # Wrong! Don't mutate
```

Instead: return a dict; Protean merges it into extensions.

### Unsafe context access

```python
@domain.command_enricher
def add_ctx(command):
    return {"request_id": g.request_id}  # Raises if unset -> aborts the command
```

Instead: `getattr(g, "request_id", None)`.

### Putting business data in extensions

Extensions are for cross-cutting metadata (tenant, request, actor), not domain
payload. Domain data belongs in the command/event fields.

## Detailed references

- [Anti-patterns](references/anti-patterns.md) - Common mistakes and how to avoid them

### Complete examples

- [Command Enricher](assets/command_enricher_basic.py) - Enrich commands with request context
- [Event Enricher](assets/event_enricher_basic.py) - Enrich events with tenant + aggregate context

### Related skills

- `command` / `command-handler` - Commands that enrichers annotate
- `event` / `event-handler` - Events that enrichers annotate
- `aggregate` - Event enrichers receive the aggregate raising the event

Attribution

proteanhqproteanhq
View sourceMore from proteanhq →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →