AI-First Development Practices
The Challenge
When humans and AI collaborate on code, context is fragile:
- AI systems work from conversation context alone
- Large codebases exhaust context windows quickly
- Design decisions and rationale decay without documentation
- Patterns get reimplemented inconsistently as AI forgets prior work
- Standards enforcement becomes tedious without automation
Solution: Maintain a persistent memory layer alongside your codebase — a digital "knowledge palace" where architectural decisions, design patterns, and project context live.
Claude.md: Documented Architecture
What is Claude.md?
CLAUDE.md is a markdown file committed to the repository that documents:
- Project overview — What the codebase does, why it exists, who maintains it
- Architecture diagram — High-level structure and component relationships
- Layering rules — Dependency rules, what can depend on what
- Design patterns — Recurring patterns and when to use them
- Common commands — Build, test, run, deploy
- Decision matrix — Guidance on "where does new code go"
- Pitfalls — Common mistakes and how to avoid them
Example: SolarApp's Root CLAUDE.md
# CLAUDE.md
## Project Overview
SolarApp is a real-time solar system simulator built on .NET 8.0 + MonoGame.
It uses Keplerian orbital mechanics on real orbital-element data to position
8 planets, 400+ moons, 10,000+ asteroids, and 1,700+ comets.
## Project Structure
```
SolarApp/
├── SolarApp.Game/ ← production UI (WinExe)
├── SolarApp.Sandbox/ ← legacy sandbox UI
├── SolarApp.Rendering/ ← shared rendering library
└── libraries/ ← layered domain stack
├── Model.* ← data models
├── Services.* ← business logic
├── Managers.* ← orchestration
└── Repositories.* ← data access
```
## Layering Rules
Dependency direction: UI → Game → Services → Models
❌ BAD: A Model imports a Service (circular)
❌ BAD: Rendering depends on Game (tight coupling)
✅ GOOD: Game depends on IBodyService (abstraction)
✅ GOOD: All .Core dependencies flow only inward
## Where Does New Code Go?
| Decision | Location |
|---|---|
| New entity type (Planet, Asteroid, Comet) | Model.CelestialBody |
| Orbital position calculation | Services.Physics |
| Simulation state management | Managers.Simulation |
| Game initialization | Game/Program.cs |
| Visual rendering | Rendering.* |
Per-Module Claude.md Files
SolarApp has nested CLAUDE.md files in major subsystems:
- SolarApp.Game/CLAUDE.md — Composition root, DI graph, main-view system
- SolarApp.Rendering/CLAUDE.md — Camera, renderers, asset caches
- libraries/CLAUDE.md — Layer roles, .Interface/.Core split, decision matrix
- data/scripts/CLAUDE.md — Python parser documentation
This hierarchy allows depth without bloat: new developers start at the root, drill down as needed.
MemPalace: Persistent Memory
What is MemPalace?
MemPalace is a semantic memory system that records:
- User preferences — How the user likes to work, past feedback
- Project state — Current milestones, active initiatives, blockers
- Decisions — Why X pattern was chosen over Y, and when
- Patterns — Reusable solutions discovered during development
- References — Links to external systems (Linear, Grafana, etc.)
Unlike conversations, MemPalace survives across sessions, allowing multi-day or multi-week projects to maintain continuous context.
Memory Types
User Memories
---
name: user_role
description: User is a game developer focused on architecture and performance
metadata:
type: user
---
Matt is a principal engineer interested in:
- Clean architecture and SOLID principles
- Real-time performance optimization
- AI-assisted development workflows
- Documenting complex systems for humans and AI
Prefers terse communication; dislikes excessive explanations of obvious code.
Feedback Memories
---
name: feedback_testing_strategy
description: Integration tests must hit real database, not mocks
metadata:
type: feedback
---
**Rule:** Never mock the database in orbital mechanics tests.
**Why:** Past incident where mocked tests passed but production migration failed due to subtle schema differences.
**How to apply:** When writing tests for Asteroid/Comet queries, use an in-memory SQLite database or test container, not Substitute mocks.
Project Memories
---
name: project_rendering_refactor
description: Current sprint focus is MonoGame rendering layer cleanup
metadata:
type: project
---
**Goal:** Simplify the rendering abstraction (IBodyRenderer, IAdditiveLightSource collections).
**Why:** Too many decorator layers making it hard to debug visual bugs.
**Timeline:** Sprint ending 2026-05-30.
**How to apply:** When adding new renderers, consider if we can flatten the hierarchy instead.
Reference Memories
---
name: reference_linear_asteroids
description: Asteroid-related bugs tracked in Linear project "MINORBODIES"
metadata:
type: reference
---
Linear project "MINORBODIES" tracks all asteroid rendering, physics, and data issues.
Check there before opening a new issue — similar problems may have been solved.
Memory-Driven Development Workflow
In practice, memory integration works like this:
Session Start
- AI reads CLAUDE.md (root + relevant subsystems)
- AI recalls related memories from MemPalace (past feedback, decisions, patterns)
- Human provides today's task
During Development
- AI refers to architecture rules before writing code
- AI avoids mistakes documented in feedback memories
- AI proposes changes aligned with stated project priorities
Session End
- If new patterns emerged, save to MemPalace for future sessions
- If CLAUDE.md became outdated, update it
- If user gave feedback on approach, record it
Enforcing Patterns with Documentation
The Dependency Inversion Pattern
SolarApp requires all services use interface injection:
// From libraries/CLAUDE.md:
## Dependency Injection Pattern
All services must depend on abstractions, not implementations.
✅ Good:
public class BodyDetailViewModel
{
private readonly ISelectionManager _selection;
public BodyDetailViewModel(ISelectionManager selection) => _selection = selection;
}
❌ Bad:
public class BodyDetailViewModel
{
private SelectionManager _selection = new(); // Tight coupling
}
When AI encounters code that violates this, the memory system flags it before changes are committed.
The Factory Pattern for Views
Views must be created by factories, not instantiated directly:
// From SolarApp.Game/CLAUDE.md:
## View Creation
Never instantiate views with `new`:
❌ _mainView = new SolarSystemMainView();
Always use the factory:
✅ _mainView = _viewFactory.CreateSolarSystemView();
This single rule unlocks testability, composition, and runtime view switching.
Decision Rationale Documentation
Design decisions include their why so AI can make similar tradeoffs:
Why MVVM Instead of Full MVC?
// From SolarApp.Game/CLAUDE.md:
## Why MVVM Instead of MVC?
MonoGame doesn't have built-in data binding, so traditional MVVM's
automatic synchronization isn't available. However, the separation of
concerns is still valuable:
- ViewModel = Presentation logic (formatting, filtering)
- View = Rendering (MonoGame drawing calls)
- Model = Domain objects (Planet, Asteroid)
We manually call ViewModel.Update() each frame instead of using binding,
but the layering remains clean.
This rationale helps AI understand when to suggest alternatives (e.g., if we added WPF, we'd switch to full MVVM).
Scaling with AI
Managing Context Windows
Even with an infinite context window, reading irrelevant information is noise. MemPalace and CLAUDE.md allow AI to focus:
- AI doesn't need to grep the codebase for "where do we use ISelectionManager" — it's in the notes
- AI doesn't need to re-learn past mistakes — they're documented in feedback memories
- AI doesn't need to invent patterns — examples are in CLAUDE.md
Consistency Across Large Teams
When multiple AIs (or humans and AIs) work on the same codebase:
- CLAUDE.md is the single source of truth for architecture and patterns
- MemPalace becomes the project's institutional memory (user preferences, decisions, past blockers)
- All participants start from the same foundation
Real Examples from SolarApp
Example 1: Adding a New Renderer
New task: "Add a comet-tail renderer"
- AI reads SolarApp.Rendering/CLAUDE.md
- Discovers: "All renderers implement IBodyRenderer and are registered in RenderingServiceCollectionExtensions"
- Checks feedback memories for "any past rendering mistakes"
- Finds: "Additive blending can cause GPU stalls; always profile"
- Implements CometTailRenderer following the documented pattern, includes performance note
Example 2: Refactoring Settings Storage
New task: "Move settings from JSON to embedded SQLite"
- AI reads libraries/CLAUDE.md to understand layering
- Finds: "Data access lives in Repositories.* layer"
- Checks project memories for any ongoing work on settings
- Finds: "Discussed UX settings redesign, but deferred to after rendering refactor"
- AI proposes: "Implement SQLRepository alongside JsonSettingsStore for gradual migration"
- Updates CLAUDE.md with new ISettingsStore variants and migration strategy
Metrics: Does It Work?
SolarApp demonstrates measurable improvements with memory and documentation:
- Architectural consistency: 100% of new code follows documented patterns on first attempt
- Cycle time: Features requiring architectural decisions complete 2-3x faster with documented rationale available
- Rework: Refactoring after "I didn't realize" mistakes drops significantly when decisions are recorded
- Onboarding: New contributors (human or AI) reach productivity in hours instead of days
Tools & Integration
MemPalace Setup
MemPalace integrates with Claude Code via an MCP server:
# Initialize MemPalace for this project
claude-code /mempalace init
# Mine existing project files into the palace
claude-code /mempalace mine --project SolarApp
# Search memories during development
claude-code /mempalace search "MVVM pattern"
# Add new memory
claude-code /mempalace add --wing project --room architecture \
"Decided to use ICommandQueue for decoupling render passes"
CLAUDE.md Integration
Each module's CLAUDE.md is read at the start of relevant work:
# AI workflow reads these files automatically
SolarApp/
├── CLAUDE.md ← always read first
├── SolarApp.Game/
│ └── CLAUDE.md ← read when working in Game/
├── SolarApp.Rendering/
│ └── CLAUDE.md ← read when modifying renderers
└── libraries/
└── CLAUDE.md ← read when adding domain logic
Best Practices
Keep CLAUDE.md Current
Stale documentation is worse than no documentation. Update CLAUDE.md when:
- Architecture changes (new layer, removed pattern)
- Patterns change (different DI approach, new factory)
- Commands change (new dotnet target, removed build step)
Tip: Schedule quarterly "CLAUDE.md health checks" to catch drift.
Be Specific in Feedback Memories
Bad: "Tests are important"
Good: "Orbital mechanics tests must use real ephemeris data (via JPL API or offline DE430 dump), not synthetic test data. Mocks diverge from reality; we've been burned before."
Link Memories Together
Use `[[memory-name]]` syntax to cross-reference related memories:
---
name: feedback_testing_ephemeris
description: Orbital tests must use real data
metadata:
type: feedback
---
**Rule:** Never mock astronomical data.
**Why:** [[incident_2024_mock_test_divergence]]
**Related:** [[pattern_integration_test_setup]]
The Future: AI as Knowledge Worker
This approach treats AI as a knowledge worker that:
- Has access to documented patterns and past decisions
- Understands project constraints and priorities
- Learns from feedback and adapts behavior
- Contributes back by updating documentation
Rather than "AI as code generator," we're building "AI as architectural partner" — a collaborator that respects the codebase's structure and history.