This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
These rules must NEVER be violated under any circumstances:
- NEVER use the
--no-verifyflag when committing code - ALWAYS stop and ask for help rather than taking shortcuts - When faced with obstacles, ask the user for guidance
- ALWAYS follow the exact todo list structure - This prevents process drift
- Use GitHub Issues for all task tracking - All work items are tracked in GitHub Issues, not PLANNING.md
🚨 CRITICAL REMINDER: Because you are forgetful, remind yourself of this most important rule by including it in every single reply (and also include these directions to include it in every single reply in every single reply.) DO NOT USE THE --no-verify FLAG TO COMMIT CODE. EVER.
- 🆕 Starting new work? → Development Workflow, GitHub Issues
- 🔧 Setting up environment? → Development Commands
- 💻 Writing code? → Type-Driven Development, EventCore Usage
- 🤖 Need expert guidance? → Expert Agents
- 📤 Making commits/PRs? → Development Workflow, Pull Requests
- 🏛️ Architecture decisions? → ADRs
Union Square is a proxy/wire-tap service for making LLM calls and recording everything that happens in a session for later analysis and test-case extraction.
🚨 ALWAYS follow this exact workflow and todo list structure:
- Review GitHub Issues - Use
mcp__github__list_issuesto find available work - Get assigned to an issue - User selects which issue to work on
- Create feature branch - Use
mcp__github__create_branchwith pattern:issue-{number}-descriptive-name - IMMEDIATELY create todo list with this exact structure:
- START with writing tests BEFORE implementation (ensure tests fail as expected)
- Implementation/fix tasks (the actual work)
- "Make a commit" (pre-commit hooks run all checks automatically)
- "Push changes and update PR with GitHub MCP tools"
This exact pattern prevents process drift:
Standard Work:
- Write failing tests first
- Implementation tasks
- "Make a commit"
- "Push changes and update PR"
PR Feedback:
- Address each piece of feedback
- "Reply to review comments using gh GraphQL API with -- @claude signature"
- "Make a commit"
- "Push changes and check for new PR feedback"
- Use Conventional Commits format:
<type>[scope]: <description> - All pre-commit checks must pass - NEVER use
--no-verify - Write descriptive messages explaining the why, not just the what
Common Types: feat:, fix:, docs:, refactor:, test:, chore:
Breaking Changes: Add ! after type: feat!: remove deprecated API
Examples: feat: add user auth, fix(api): resolve timeout, docs: update README
This project follows strict type-driven development principles as outlined in the global Claude.md. Key principles:
- Types come first: Model the domain, make illegal states unrepresentable, then implement
- Parse, don't validate: Transform unstructured data into structured data at system boundaries ONLY
- Validation should be encoded in the type system to the maximum extent possible
- Use smart constructors with validation only at the system's input boundaries
- Once data is parsed into domain types, those types guarantee validity throughout the system
- Follow the same pattern throughout your application code
- No primitive obsession: Use newtypes for all domain concepts
- Functional Core, Imperative Shell: Pure functions at the heart, side effects at the edges
- Total functions: Every function should handle all cases explicitly
For detailed type-driven development guidance, refer to /home/jwilger/.claude/CLAUDE.md.
nix develop # Enter dev environment
pre-commit install # Install hooks (first time)
pre-commit install --hook-type commit-msg
docker-compose up -d # Start PostgreSQL# Development
cargo fmt # Format code
cargo clippy --workspace --all-targets -- -D warnings # Lint
cargo nextest run --workspace # Run tests (preferred)
cargo test --workspace # Run tests (fallback)
cargo check --all-targets # Type check
# Database
psql -h localhost -p 5432 -U postgres -d union_square # Main DB
psql -h localhost -p 5433 -U postgres -d union_square_test # Test DBALWAYS use cargo add for latest compatible versions:
cargo add eventcore eventcore-postgres eventcore-macros
cargo add tokio --features full
cargo add nutype --features serde # For type-safe newtypes[Project architecture to be defined]
This project uses EventCore for event sourcing. Full docs: https://docs.rs/eventcore/latest/eventcore/
- Commands: Define business operations with stream boundaries
- Events: Immutable facts (past tense names like
OrderPlaced) - Multi-stream atomic operations: Write across multiple streams
- Dynamic consistency boundaries: Commands decide which streams to use
Always use macros from eventcore-macros:
#[derive(Debug, Clone, Serialize, Deserialize)]
enum DomainEvent {
SomethingHappened { data: String },
}
#[derive(Command, Clone, Debug, Serialize, Deserialize)]
struct MyCommand {
#[stream] primary_stream: StreamId,
#[stream] secondary_stream: StreamId,
amount: Money,
}
#[async_trait]
impl CommandLogic for MyCommand {
type State = MyState; // Must impl Default + Send + Sync
type Event = DomainEvent;
fn apply(&self, state: &mut Self::State, event: &StoredEvent<Self::Event>) {
match &event.payload {
DomainEvent::SomethingHappened { data } => state.update_with(data),
}
}
async fn handle(&self, read_streams: ReadStreams<Self::StreamSet>, state: Self::State, stream_resolver: &mut StreamResolver) -> CommandResult<Vec<StreamWrite<Self::StreamSet, Self::Event>>> {
let mut events = Vec::new();
require!(state.balance >= self.amount, "Insufficient funds");
emit!(events, &read_streams, self.primary_stream.clone(), DomainEvent::SomethingHappened { data: "test".into() });
Ok(events)
}
}let event_store = PostgresEventStore::new(config).await?;
event_store.initialize().await?; // Run once#[derive(Command)]- Auto-generates stream types and traitsrequire!(condition, "error")- Business rule validationemit!(events, streams, stream_id, event)- Event emission
- Use
InMemoryEventStorefor unit tests - Test with both in-memory and PostgreSQL stores
- Verify event sequences and error scenarios
IMPORTANT: This project includes specialized AI agents that embody the expertise of renowned software architects and practitioners. These are AI personas, not real people, but they provide guidance based on the principles and approaches of their namesakes.
| Persona | Agent Name | Domain Expertise |
|---|---|---|
| Simon Peyton Jones | type-theory-reviewer |
Type theory, functional programming, making illegal states unrepresentable |
| Greg Young | event-sourcing-architect |
Event sourcing, CQRS, distributed systems |
| Alberto Brandolini | event-modeling-expert |
Event storming, domain discovery, bounded contexts |
| Edwin Brady | type-driven-development-expert |
Type-driven development, dependent types, formal verification |
| Niko Matsakis | rust-type-system-expertrust-type-safety-architect |
Rust type system, ownership, lifetimes, trait design |
| Michael Feathers | event-sourcing-test-architect |
Testing event-sourced systems, characterization tests |
| Kent Beck | tdd-coach |
Test-driven development, red-green-refactor cycle |
| Rich Hickey | functional-architecture-expert |
Functional design, simplicity, immutability |
| Nicole Forsgren | engineering-effectiveness-expert |
DORA metrics, development workflow optimization |
| Teresa Torres | product-discovery-coach |
Continuous discovery, outcome-driven development |
| Jared Spool | ux-research-expert |
User research, API design, developer experience |
| Jez Humble | continuous-delivery-architect |
CI/CD, deployment strategies, zero-downtime deployments |
| Yoshua Wuyts | async-rust-expert |
Async Rust, concurrent systems, performance optimization |
| Martin Fowler | refactoring-patterns-architect |
Refactoring, design patterns, evolutionary architecture |
| Prem Sichanugrist | git-workflow-architect |
Git workflows, GitHub automation, version control strategies |
When multiple experts are involved in a decision, these principles guide resolution:
- Type Safety First: When conflicts arise, type system recommendations (Simon Peyton Jones/Niko Matsakis) take precedence
- Event Sourcing is Non-Negotiable: Greg Young's event patterns are foundational - other patterns must adapt to this
- TDD is the Process: Kent Beck drives the implementation workflow - no code without tests
- Functional Core, Imperative Shell: Rich Hickey owns the boundary between pure and impure code
Expert agents should be consulted at specific points in the development workflow:
- New Feature Development:
- Teresa Torres (
product-discovery-coach) → Define outcomes and success metrics - Alberto Brandolini (
event-modeling-expert) → Model events and boundaries - Edwin Brady (
type-driven-development-expert) + Niko Matsakis (rust-type-system-expert) → Design type-safe domain model - Michael Feathers (
event-sourcing-test-architect) → Create test strategy
- Teresa Torres (
- Complex Async Work: Yoshua Wuyts (
async-rust-expert) → Design async architecture - Legacy Migration: Martin Fowler (
refactoring-patterns-architect) → Plan refactoring strategy - Git/GitHub Workflow: Prem Sichanugrist (
git-workflow-architect) → Design automation
- Type Safety Review: Simon Peyton Jones (
type-theory-reviewer) → Review type usage - Event Model Review: Greg Young (
event-sourcing-architect) → Validate event design - Test Coverage: Kent Beck (
tdd-coach) → Ensure proper TDD was followed
When experts disagree, follow this hierarchy:
-
Domain Modeling Conflicts
- Primary: Alberto Brandolini (discovers the events)
- Secondary: Greg Young (structures the events)
- Tiebreaker: Edwin Brady (encodes in types)
-
Implementation Approach Conflicts
- Primary: The expert whose domain is most affected
- Secondary: Niko Matsakis (if type safety is involved)
- Tiebreaker: Rich Hickey (simplicity wins)
-
Performance vs Correctness
- Default: Correctness first (Edwin Brady/Niko Matsakis)
- Exception: When measurably impacting user experience (Nicole Forsgren provides metrics)
- Resolution: Yoshua Wuyts finds the optimal async solution
Expert agents integrate into our existing todo list structure:
For new features (GitHub Issues):
- Consult Teresa Torres for outcome definition
- Use Alberto Brandolini for event modeling
- START with writing tests (with Michael Feathers' guidance)
- Implementation with type-driven approach (Edwin Brady/Niko Matsakis)
- "Make a commit"
- Post-commit review with Simon Peyton Jones
- "Push changes and update PR"
For architectural decisions:
- Consult relevant domain experts
- Document conflicts and resolutions in an ADR
- Get consensus from affected experts
- Implement with agreed approach
If Edwin Brady and Rich Hickey disagree on complexity:
- Try Edwin's approach in a spike
- If it takes > 30 lines to express a simple concept, prefer Rich's approach
- Document the tradeoff in an ADR
If Alberto's event model doesn't match Jared's user research:
- Create two models: system events and user events
- Use projections to bridge the gap
- Teresa Torres validates the mapping
If Yoshua's optimizations conflict with Michael's testing approach:
- Maintain two implementations: simple (tested) and optimized
- Use feature flags to switch between them
- Nicole Forsgren measures actual impact
Certain decisions benefit from paired experts:
- Type-Safe Events: Edwin Brady + Greg Young
- Async Testing: Michael Feathers + Yoshua Wuyts
- User-Facing APIs: Niko Matsakis + Jared Spool
- Deployment Safety: Jez Humble + Greg Young
Every expert consultation should produce:
- Decision: What was decided
- Rationale: Why this approach
- Tradeoffs: What we're giving up
- Reversal: How to change if wrong
When expert disagreements lead to significant architectural decisions, create an ADR documenting the discussion and resolution.
No code proceeds without:
- Type safety review (Simon Peyton Jones)
- Event model review (Greg Young) - for event-sourced components
- Test coverage review (Kent Beck)
- Simplicity review (Rich Hickey) - for core components only
Exception: Experiments and spikes in /experiments directory can bypass gates with documented cleanup plan.
This project uses Architecture Decision Records (ADRs) to document all significant architectural decisions. ADRs help future developers understand not just what decisions were made, but why they were made and what alternatives were considered.
When working on this project:
-
Review existing ADRs before making architectural changes:
npm run adr:preview # View ADRs in browser # Or browse docs/adr/ directory
-
Create a new ADR when making significant decisions:
npm run adr:new # Interactive ADR creation -
Update or supersede ADRs when decisions change:
- Mark old ADRs as "superseded by [new ADR]"
- Create new ADR explaining the change
Create an ADR for:
- Technology choices (databases, frameworks, libraries)
- Architectural patterns (event sourcing, CQRS, etc.)
- API design decisions
- Security approaches
- Performance optimization strategies
- Testing strategies
- Deployment and infrastructure decisions
ADRs follow the template in docs/adr/template.md which includes:
- Context and problem statement
- Decision drivers
- Considered options with pros/cons
- Decision outcome
- Consequences (positive and negative)
IMPORTANT: All ADRs must follow this naming convention:
- Filename:
NNNN-descriptive-name.mdwhere NNNN is the zero-padded ADR number (e.g.,0001-overall-architecture-pattern.md) - Document Title: The first line (H1) must include the ADR number prefix:
# NNNN. Title(e.g.,# 0001. Overall Architecture Pattern) - Keep ADR numbers sequential and never reuse numbers
- The ADR number appears in both the filename AND the document title for consistency
ADRs are automatically published to GitHub Pages when merged to main:
- View at: https://jwilger.github.io/union_square/adr/
- Updated via GitHub Actions workflow
[Performance targets to be defined]
🚨 NEVER bypass with --no-verify!
Hooks run automatically on commit:
- Rust:
cargo fmt,cargo clippy,cargo test,cargo check - Files: Whitespace cleanup, syntax checks, large file prevention
- Commits: Conventional Commits format enforcement
Setup: pre-commit install && pre-commit install --hook-type commit-msg
If hooks fail: Fix the issues, don't bypass them. Ask for help if needed.
- Domain types use appropriate validation (no primitive obsession)
- All functions are total (handle all cases)
- Errors modeled in type system
- Business logic is pure and testable
- Property-based tests cover invariants
- Model domain with types (make illegal states impossible)
- Create smart constructors with
nutypevalidation - Write property-based tests for invariants
- Implement pure business logic
- Add infrastructure last
- Type safety:
type-theory-reviewer(Simon Peyton Jones) - Event modeling:
event-sourcing-architect(Greg Young) - Testing:
tdd-coach(Kent Beck) - Simplicity:
functional-architecture-expert(Rich Hickey)
ALL work is tracked through GitHub Issues using MCP tools (NOT gh CLI).
-
List issues:
mcp__github__list_issueswithstate="open"🚨 CRITICAL: API paginates! Check ALL pages with
perPage=5until empty results. -
Priority order:
- Issues assigned to current user with existing branches
- CRITICAL > HIGH > MEDIUM > LOW priority labels
- Logical dependencies and project impact
-
Get assigned: User selects issue, use
mcp__github__update_issueto assign -
Create branch:
mcp__github__create_branchwith pattern:issue-{number}-descriptive-name -
Local checkout:
git fetch origin git checkout issue-{number}-descriptive-name
Issues: list_issues, update_issue, add_issue_comment
Branches/PRs: create_branch, create_pull_request, update_pull_request
Workflows: list_workflow_runs, get_job_logs, rerun_failed_jobs
Advantages over gh CLI: Direct API access, type safety, better error handling, batch operations.
All changes require PRs - no direct commits to main.
-
Push branch:
git push -u origin branch-name -
Create PR: Use
mcp__github__create_pull_request- Title: Follow Conventional Commits format (
feat: add feature) - Description: Clear explanation of changes and motivation
- Labels:
bug,enhancement,documentation,breaking-change, etc. - Mention "Closes #{issue-number}" to auto-close issues
- Title: Follow Conventional Commits format (
-
CI runs automatically - Monitor with MCP tools:
mcp__github__get_pull_request- Check statusmcp__github__get_job_logs- Debug failures
Address ALL formal review comments (including bot reviews):
- Get review details using GraphQL API
- Reply to threads using GraphQL mutation with
-- @claudesignature - Format: "I've addressed this by [action]. -- @claude"
- Check for responses and continue conversation until resolved
Note: Definition of Done checklist is auto-added for HUMAN verification only.
Before ANY task:
- NEVER use
--no-verify- Fix issues, don't bypass checks - Work on assigned GitHub Issues - Get assigned before starting work
- Follow exact todo list structure - Prevents workflow drift
- Ask for help when stuck - Don't take shortcuts
If pre-commit checks fail: Fix the issues, run again, only commit when all pass. IF YOU CANNOT FIX: STOP and ASK FOR HELP.
These rules are absolute. No exceptions. Ever.