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

Event

ASecurity

Define a Protean domain event - an immutable fact representing a state change in the business domain. Events capture meaningful changes to aggregates and enable decoupled communication between system components. Events are always associated with aggregates and are named in past-tense (OrderPlaced, CustomerRegistered). Use when you need to record what happened in your domain, when you want to communicate state changes to other parts of the system, when the user asks to "create an event", "defi...

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

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

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

Installs into .claude/skills of the current project.

Are you the author of Event?

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

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

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

Download Zip
Files
SKILL.md
---
name: event
description: Define a Protean domain event - an immutable fact representing a state change in the business domain. Events capture meaningful changes to aggregates and enable decoupled communication between system components. Events are always associated with aggregates and are named in past-tense (OrderPlaced, CustomerRegistered). Use when you need to record what happened in your domain, when you want to communicate state changes to other parts of the system, when the user asks to "create an event", "define a domain event", "add an event", when implementing event sourcing or CQRS patterns, or when they describe something that occurred (like "order was placed", "payment confirmed", "inventory depleted"). Events can be delta events (incremental changes) or fact events (complete state snapshots).
license: Apache-2.0
compatibility: Requires Python 3.11+, protean framework
metadata:
  author: proteanhq
  version: "0.1"
  category: element
---

# Event

## Basic structure

An event is defined using the `@domain.event(part_of="...")` decorator:

```python
from protean import Domain
from protean.fields import String, DateTime

domain = Domain()

@domain.event(part_of="Order")
class OrderPlaced:
    __version__ = 1

    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    placed_at: DateTime(required=True)
```

## Key rules

1. **Events must be associated with aggregates** - Always specify `part_of` parameter with the aggregate name
2. **Events are named in past-tense** - Use past-tense verbs: `OrderPlaced`, not `PlaceOrder`
3. **Events are immutable** - Once created, events cannot be modified (they are facts)
4. **Events are DTOs** - Can contain simple fields and value objects, but NOT entities or aggregates
5. **Events should be lightweight** - Include only data necessary to describe what happened
6. **Events are versioned** - Use `__version__` class attribute for schema evolution (defaults to `1`)
7. **Events have metadata** - Protean automatically adds timestamps, unique IDs, and versioning
8. **Events are raised from aggregates** - Use `self.raise_()` method within aggregate methods
9. **Events are persisted to streams** - Events are written to aggregate-specific streams
10. **Events enable decoupling** - Other components react to events via event handlers

## Event types

### Delta Events
Delta events capture incremental changes to aggregate state. Most events are delta events.

```python
@domain.event(part_of="Order")
class OrderPlaced:
    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    total_amount: Float(required=True)
```

### Fact Events
Fact events contain complete aggregate state at a point in time (Event-carried State Transfer pattern).

```python
@domain.event(part_of="Order")
class OrderSnapshot:
    """Complete order state for consumers."""
    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    status: String(required=True)
    items: List()  # Full state
    total = ValueObject(Money)
```

## Fields and versioning

### Simple Fields

```python
from protean.fields import String, Integer, Float, DateTime, Boolean

@domain.event(part_of="Product")
class ProductCreated:
    __version__ = 1

    product_id: String(required=True, identifier=True)
    name: String(required=True, max_length=200)
    price: Float(required=True)
    created_at: DateTime(required=True)
```

### With Value Objects

Events can contain value objects for complex immutable data:

```python
@domain.value_object
class Money:
    amount: Float(required=True)
    currency: String(max_length=3, default="USD")

@domain.event(part_of="Order")
class OrderPlaced:
    __version__ = 1

    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    total = ValueObject(Money, required=True)
    placed_at: DateTime(required=True)
```

### Event Versioning

Use `__version__` for schema evolution:

```python
@domain.event(part_of="Order")
class OrderPlaced:
    __version__ = 1

    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)

# Later, when schema evolves
@domain.event(part_of="Order")
class OrderPlaced:
    __version__ = 2

    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    total = ValueObject(Money)  # New field in v2
```

## Raising events from aggregates

Events are raised within aggregate methods using `self.raise_()`:

```python
from datetime import datetime, timezone

@domain.aggregate
class Order:
    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    status: String(default="draft")
    total = ValueObject(Money)

    def place(self):
        if self.status != "draft":
            raise ValueError("Order already placed")

        self.status = "placed"
        placed_at = datetime.now(timezone.utc)

        # Raise event - automatically associated with this aggregate instance
        self.raise_(OrderPlaced(
            order_id=self.order_id,
            customer_id=self.customer_id,
            total=self.total,
            placed_at=placed_at
        ))
```

## Quick example

```python
from protean import Domain
from protean.fields import String, Float, DateTime, ValueObject
from datetime import datetime, timezone

domain = Domain()

@domain.value_object
class Money:
    amount: Float(required=True)
    currency: String(max_length=3, default="USD")

@domain.event(part_of="Order")
class OrderPlaced:
    __version__ = 1

    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    total = ValueObject(Money, required=True)
    placed_at: DateTime(required=True)

@domain.aggregate
class Order:
    order_id: String(required=True, identifier=True)
    customer_id: String(required=True)
    status: String(default="draft")
    total = ValueObject(Money)

    def place(self):
        if not self.total or self.total.amount <= 0:
            raise ValueError("Order must have a positive total")
        if self.status != "draft":
            raise ValueError("Order already placed")

        self.status = "placed"

        # Raise event
        self.raise_(OrderPlaced(
            order_id=self.order_id,
            customer_id=self.customer_id,
            total=self.total,
            placed_at=datetime.now(timezone.utc)
        ))

# Usage
order = Order(
    order_id="ORD-001",
    customer_id="CUST-123",
    total=Money(amount=99.99, currency="USD")
)
order.place()
print(f"Order {order.order_id} placed. Events: {len(order._events)}")
```

## Common mistakes

### ❌ Using imperative verbs instead of past-tense

```python
@domain.event(part_of="Order")
class PlaceOrder:  # Wrong! This is a command name
    pass
```

✅ **Instead: Use past-tense verbs**

```python
@domain.event(part_of="Order")
class OrderPlaced:  # Correct! Past-tense
    pass
```

### ❌ Not associating event with aggregate

```python
@domain.event  # Wrong! Missing part_of
class OrderPlaced:
    pass
```

✅ **Instead: Always specify part_of**

```python
@domain.event(part_of="Order")  # Correct!
class OrderPlaced:
    pass
```

### ❌ Including entities in events

```python
@domain.event(part_of="Order")
class OrderPlaced:
    order_entity = HasOne(OrderEntity)  # Wrong! Events can't contain entities
```

✅ **Instead: Only fields and value objects**

```python
@domain.event(part_of="Order")
class OrderPlaced:
    order_id: String(required=True, identifier=True)
    total = ValueObject(Money)  # OK - value objects are allowed
```

### ❌ Including too much unnecessary data

```python
@domain.event(part_of="Order")
class OrderPlaced:
    # Including entire customer object when only ID is needed
    customer_name: String()
    customer_email: String()
    customer_address: String()
    customer_phone: String()
```

✅ **Instead: Only necessary information**

```python
@domain.event(part_of="Order")
class OrderPlaced:
    customer_id: String(required=True)  # Just the ID
```

### ❌ Making events mutable

```python
event = OrderPlaced(order_id="123", customer_id="456")
event.order_id = "789"  # Wrong! Events are immutable
```

✅ **Instead: Events are immutable facts**

```python
event = OrderPlaced(order_id="123", customer_id="456")
# Cannot modify - event is immutable and represents what happened
```

## Detailed references

### Core Concepts
- [Delta Events](references/delta-events.md) - Incremental state changes
- [Fact Events](references/fact-events.md) - Complete state snapshots (Event-carried State Transfer)
- [Events with Value Objects](references/with-value-objects.md) - Using value objects in events
- [Event Versioning](references/event-versioning.md) - Schema evolution and version management
- [Raising Events](references/raising-events.md) - How to raise events from aggregates
- [Anti-patterns](references/anti-patterns.md) - Common mistakes and how to avoid them

### Complete Examples
- [Simple Delta Event](assets/event_simple.py) - Basic event with minimal fields
- [Event with Value Objects](assets/event_with_value_object.py) - Events containing value objects
- [Fact Event](assets/event_fact.py) - Complete state snapshot event
- [Event Versioning](assets/event_versioning.py) - Schema evolution examples
- [Raising Events](assets/raising_events.py) - Complete example with aggregate raising events

### Related Skills
- `aggregate` - Events are always part of aggregates
- `value-object` - Events can contain value objects
- `event-handler` - How events are consumed and processed
- `patterns/event-sourcing` - Using events as the source of truth
- `patterns/cqrs` - Using events for read model updates

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 →