tmchow/hzl
Overview
This skill enforces event sourcing patterns for hzl code so all state mutations flow through EventStore.append() and projections remain read-only derived views. It codifies rules for event immutability, projection rebuildability, and proper service-layer orchestration. The goal is consistent, auditable state and reliable projection behavior across features.
How this skill works
The skill inspects code to ensure state changes are only expressed as events appended to EventStore and that projection tables are only updated by projectors. It checks that new event types include Zod schemas, that projectors implement initialize/apply patterns, and that services append events instead of writing directly to projection tables. It also flags unsafe patterns like direct DB updates, projector side effects, and missing transactional boundaries.
When to use it
- When adding or modifying features that change application state
- When introducing new event types or payloads
- When creating or updating projectors that maintain projection tables
- When implementing service-layer business logic that orchestrates state changes
- When reviewing pull requests for compliance with event sourcing rules
Best practices
- Always record state changes as events via EventStore.append(); never write directly to projections
- Define event types in events/types.ts and add Zod schemas for validation
- Implement projector initialize() for table creation and apply() for idempotent updates
- Keep projections strictly read-only and derivable from replaying all events
- Use withWriteTransaction() for atomic read-modify-write sequences to avoid races
Example use cases
- Create a Task: add TaskCreated event type, validate with Zod, append event from TaskService, let projectors update tasks_current
- Change Status: append a StatusChanged event instead of running direct UPDATE on tasks_current
- Add a new projection: write a projector with initialize/apply and ensure it can be rebuilt from existing events
- Concurrent updates: wrap read-modify-append operations in withWriteTransaction() to guarantee consistency
FAQ
Projections are cached, derived views rebuilt from events. Making them read-only ensures the event stream remains the single source of truth and avoids divergence.
Where do timestamps belong?
Timestamps belong in events at append time so they are immutable facts; projectors should not generate or modify timestamps.