Building Your AI Development Constitution: The Essential Framework
In Article 1, we talked about the uncomfortable truth: AI coding assistants are making most developers 19% slower, not faster.
We covered the six problems:
- The Performance Trap (verification overhead)
- The Code Quality Death Spiral
- The Attention Problem (information overload)
- The Context Problem (AI doesn’t know your project)
- The Trust Problem (hallucinations and false confidence)
- The Security Problem (45% vulnerability rate)
If you did the homework — tracking one coding session — you probably saw these problems in your own work.
Now let’s fix them.
In this article, I’m going to lay out the foundation for effective AI-assisted development. This is the system I use across all my projects. It’s what takes my Claude Code sessions from “sometimes helpful” to “reliable development partner.”
The Core Principle
Before we dive into specifics, you need to understand the fundamental principle:
Treat your AI assistant like a capable junior developer who needs clear direction, context, and verification.
Not a magic box. Not a senior engineer. A skilled team member who needs structure.
Once you accept this, everything else makes sense.
The Foundation: Your CLAUDE.md File
Every project I work on has a CLAUDE.md file in the root directory. Think of it as a constitution—the rules of engagement for how AI operates in this project.
This one file solves multiple problems at once:
- Context Problem: AI knows the project structure and conventions
- Trust Problem: Clear authority hierarchy for when documents conflict
- Quality Problem: Explicit standards that must be met
Let me show you what goes in it.
The Authority Hierarchy
Here’s how I start every CLAUDE.md:# CLAUDE.md - Project Development Guide
## CRITICAL: Document Authority
**This hierarchy determines which document to trust when they conflict:**
1. **PRD.md** = Source of truth (ALWAYS authoritative)
2. **CLAUDE.md** = How to work (this file)
3. **next_session_plan.md** = What's next (can be wrong)
4. **Session logs** = History (can contain mistakes)
**Before writing ANY code, you MUST:**
1. Read PRD.md (at minimum lines 1-100)
2. Read the "What This Is NOT" section
3. Read current phase definition
4. THEN read next_session_plan.md
5. If there's a conflict, STOP and ask me immediately
Why does this matter so much?
Because without it, when your session plan says one thing and your PRD says another, the AI has no way to know which to trust. It’ll pick one at random, or worse, try to synthesize them into something that satisfies neither.
With this hierarchy, conflicts become opportunities for clarification rather than sources of wasted effort.
The “What This Project Is NOT” Section
This is one of the most powerful sections. I explicitly document what the project is NOT:## What This Project IS NOT
- ❌ **Not a REST API** - Graph only, no API layer included
- ❌ **Not an agentic system** - No LLM orchestration or autonomous agents
- ❌ **Not multi-tenant** - Single deployment
- ❌ **Not platform-specific** - Framework-focused, not AWS/Azure/GCP
Why include the negative space?
Because I’ve watched AI assistants enthusiastically build exactly what I said I didn’t want. Session plans get stale. Context gets lost. But if the prohibition is right there in the constitution? It stops and asks before going down the wrong path.
Real example from my Agentic Controls project:
A session plan suggested building a REST API. Seemed reasonable — APIs are useful, right?
But the CLAUDE.md file was explicit: “Not a REST API — graph database is the deliverable.”
Claude Code detected the conflict. Stopped. Asked:
“Session plan suggests building a REST API, but PRD lines 51–58 prohibit this. Should I proceed with PRD Phase 2 instead, or do you want to amend the PRD?”
Saved time: ~15 hours of wasted development and the frustration of deleting it all.
Cost: 30 seconds to clarify.
That’s the power of explicit boundaries.
Project-Specific Rules
Every project has its own quirks. Document them:
## Project-Specific Rules
### Database
- Use Neo4j for ALL data storage (no PostgreSQL, no SQLAlchemy)
- Node properties store all metadata
- Pydantic models for validation only
### Testing
- Use pytest for all tests
- Use pytest-asyncio for async tests
- Mock external dependencies with httpx.MockTransport
### Code Style
- Follow PEP 8
- Use ruff for linting and formatting
- Maximum line length: 100 characters
- Type hints required on all functions
``
This answers the “how should I do X?” questions before they’re asked.
Pattern 1: Test-Driven Development (The Non-Negotiable)
Remember the verification overhead problem from Article 1? The time spent reading, understanding, testing, and debugging AI-generated code?
Here’s how we eliminate it: Write tests first.
The TDD Protocol
Add this to your CLAUDE.md:
## Test-Driven Development - MANDATORY
**NEVER write production code before writing a failing test.**
### The Cycle (No Exceptions)
1. **RED Phase:** Write a failing test
- Write test cases BEFORE any implementation
- Ensure tests fail for the right reasons
- Cover edge cases, boundary conditions, error scenarios
2. **GREEN Phase:** Write minimal code to pass
- Implement ONLY what's needed to pass tests
- No premature optimization
- Keep implementation simple and clear
3. **REFACTOR Phase:** Improve code quality
- Maintain 100% test pass rate during refactoring
- Apply SOLID principles
- Ensure type hints are complete
### Coverage Requirements (Gates)
- **Minimum:** 80% code coverage for all modules
- **Target:** 85%+ overall
- **Critical paths** (auth, API calls): 100% coverage
- **100% test pass rate** required before ANY commits
Why This Solves the Verification Problem
When you write tests first:
- Verification is built into the development process
- You catch bugs before they’re integrated
- You have executable documentation of what the code should do
- Refactoring becomes safe instead of terrifying
- The AI generates code to pass YOUR tests, not arbitrary code
My real numbers:
- NPM MCP project: 762 passing tests, 85.72% coverage
- GitLab MCP project: 80%+ coverage maintained across all phases
- Security issues in code review: Zero
- Code churn: < 5%
The verification overhead that makes other developers 19% slower? It’s gone because we verify first, not after.
Example TDD Cycle with AI
Let me show you how this actually works:
Step 1: Write the failing test
# tests/unit/test_auth/test_manager.py
import pytest
from npm_mcp.auth.manager import AuthManager
@pytest.mark.asyncio
async def test_get_token_returns_cached_valid_token():
"""Should return cached token if valid and not expired."""
manager = AuthManager()
# Set up cached token
manager._token = "valid_token_123"
manager._token_expiry = datetime.now() + timedelta(hours=1)
token = await manager.get_token()
assert token == "valid_token_123"
# Should not make API call (verify with mock)
@pytest.mark.asyncio
async def test_get_token_refreshes_expired_token():
"""Should refresh token if expired."""
manager = AuthManager()
# Set up expired token
manager._token = "expired_token"
manager._token_expiry = datetime.now() - timedelta(hours=1)
# Mock the refresh call
with patch.object(manager, '_refresh_token') as mock_refresh:
mock_refresh.return_value = "new_token_456"
token = await manager.get_token()
assert token == "new_token_456"
mock_refresh.assert_called_once()
Step 2: Run the test (it should fail)
pytest tests/unit/test_auth/test_manager.py -v
# Output:
# FAILED - AttributeError: 'AuthManager' object has no attribute 'get_token'
Perfect. It fails for the right reason.
Step 3: Ask AI to implement
Now I tell Claude Code:
“Implement the AuthManager.get_token() method to pass these tests. Use the test requirements to guide implementation.”
The AI now has clear success criteria. It’s not generating arbitrary code — it’s generating code to pass MY tests.
Step 4: Run tests again
pytest tests/unit/test_auth/test_manager.py -v
# Output:
# PASSED test_get_token_returns_cached_valid_token
# PASSED test_get_token_refreshes_expired_token
Green. Ship it.
The reality is that Claude Code does all of this on its own when you instruct it to build code using TDD methodologies. Sometimes Claude will get lazy, so be sure to prompt to find the current code test coverage and pass rates. Insist that you reach a target of 80% test coverage with a 100% pass rate.
Pattern 2: Phase-Based Development
Remember the attention problem? Is the information overload from too many AI suggestions?
Here’s how we fix it: Don’t ask AI to juggle the entire project at once.
The very first activity I work on with Claude Code is developing a Product Requirements Document (PRD). I will generally brainstorm my requirements in a notepad before entering them into Claude Code. The key to success here is to instruct Claude to ask you questions about the PRD.
I have provided you with an executive summary and a set of requirements for this project. Please generate a PRD and be sure to ask me any questions that you need to clarify the final document. Remember, the quality of this document will determine the success or failure of this project. ASK QUESTIONS! ultrathink.
Once the PRD is created and I have spent time reading every single word, I have built a Claude Skill that will automate the following steps.
Breaking Work into Digestible Phases
Add this to your CLAUDE.md:
## Phase-Based Development
### Current Project Phases
**Phase 1: Foundation** (Weeks 1-2)
- Project structure
- Configuration management
- Authentication system
- HTTP client with retry logic
- Core Pydantic models
**Phase 2: MCP Server & Core Tools** (Weeks 3-4)
- FastMCP server setup
- Instance management tools
- Proxy host tools
- Certificate tools
**Phase 3: Extended Features** (Weeks 5-6)
- Stream management
- Redirections and dead hosts
- User management
- System settings
**Phase 4: Bulk Operations** (Week 7)
- Unified bulk operations tool
- Batch processing engine
- Export/import functionality
**Phase 5: Release Preparation** (Weeks 8-9)
- CI/CD pipeline
- Docker deployment
- Documentation
- Security audit
### Phase Gate Criteria (CANNOT be bypassed)
Before moving to next phase, ALL must be true:
- ✅ All phase tests written (TDD process followed)
- ✅ 100% of tests passing (no failures, no skips)
- ✅ ≥80% code coverage for phase code
- ✅ Phase documentation complete
- ✅ Session logs updated
- ✅ next_session_plan.md updated with next phase objectives
Why Gates Are Non-Negotiable
You don’t move to Phase 2 with 78% coverage. You don’t move on because “we’re close enough.”
Close enough is how technical debt accumulates.
The gate is 80%. You’re at 78%. Write two more tests.
Here’s what happens when you enforce this:
- Quality is built in, not bolted on later
- Technical debt doesn’t compound
- Each phase builds on a solid foundation
- You can confidently refactor (tests have your back)
Example Phase Structure
Let me show you a real phase definition:
# Phase 1: Foundation
## Objectives
- [ ] Set up project structure (src/, tests/, docs/)
- [ ] Configure development environment (pyproject.toml, pytest.ini)
- [ ] Implement configuration system (YAML, env vars, encryption)
- [ ] Build authentication manager with JWT token caching
- [ ] Create HTTP client with retry logic
- [ ] Define all Pydantic models for NPM resources
- [ ] Implement InstanceManager for connection pooling
- [ ] Set up structured logging with structlog
## Success Criteria
- 100% tests passing
- ≥ 80% code coverage
- All linting passes (ruff, mypy)
- Documentation complete (module docstrings, README)
- Session retrospective complete
## Deliverables
- Complete project scaffolding
- Working authentication system
- Tested HTTP client
- All data models
- Instance management
- Structured logging
## Timeline
- Days 1-3: Project structure and configuration
- Days 4-6: Authentication and HTTP client
- Days 7-9: Data models and instance manager
- Day 10: Testing, documentation, retrospective
Notice how specific this is. Not “set up project” but precisely what that means with clear deliverables and success criteria.
Pattern 3: Session Management (Context is King)
Claude Code doesn’t remember your last session. It can’t. Context windows are limited, and sessions are reset.
In fact, you want to avoid auto-context compaction as much as possible. While Anthropic puts a lot of effort into preserving the proper context, it doesn’t always get it right.
Reset the context after every session…
…but give Claude memory.
The Session Protocol
Add this to your CLAUDE.md:
## Session Management Protocol
### At Session Start (MANDATORY)
1. Read previous session summary from `.claude/sessions/session_[n].md`
2. Review current phase documentation in `.claude/phases/phase_[n].md`
3. Check test suite status: `pytest --collect-only`
4. Identify blocked items from previous session
5. Load relevant context from `.claude/context/`
### During Session (Continuous)
1. Document ALL decisions in session log
2. Track completed tasks using TodoWrite tool
3. Note any deviations from plan with rationale
4. Record questions and ambiguities for clarification
5. Update metrics continuously (tests written, coverage, LOC)
### At Session End (BEFORE context reset)
1. Run full test suite: `pytest -v --cov=src --cov-report=term-missing`
2. Ensure minimum 80% coverage maintained
3. Create session summary with:
- Work completed (specific, measurable)
- Tests written/passing
- Code coverage metrics
- Blockers encountered
- Decisions made with RATIONALE
- Next session plan
4. Update phase progress in `.claude/phases/phase_[current].md`
5. Commit all changes with conventional commit messages
The Session Log Template
Create .claude/sessions/session_1.md:
# Session 1 - Project Initialization
**Date:** 2025-11-01
**Phase:** Phase 1 - Foundation (Initialization)
**Duration:** 2.5 hours
**Status:** ✅ Complete
## Session Objectives
**Primary:** Initialize NPM MCP Server project with complete dev infrastructure
**Secondary:** Set up project scaffolding and configuration ready for Phase 1
## Context Loaded
- PRD v1.1 (complete product requirements)
- Tool Catalog (28 MCP tools specification)
- Research Summary (NPM API analysis)
- Project Initialization Skill
## Work Log
### 2025-11-01 10:00 - Task Started: Project Analysis
**Approach:** Read all existing documentation (PRD, Tool Catalog, README)
**Findings:**
- Project has comprehensive documentation (200+ pages)
- 5 implementation phases clearly defined
- Technology stack selected (Python 3.11+, MCP SDK, httpx, Pydantic)
- Documentation phase complete, ready for implementation
**Result:** ✅ Success - Full understanding of project scope
### 2025-11-01 10:30 - Decision Point: Session Management Format
**Context:** Need structured session logging for context preservation
**Options Considered:**
1. Simple markdown files with free-form notes
2. Structured markdown with predefined sections
3. JSON/YAML for machine-readable format
**Choice:** Structured markdown (Option 2)
**Rationale:**
- Human-readable for developers
- Easy to create and update
- Can be parsed if needed
- Follows project-initialization skill best practices
**Impact:** Created template for all future sessions
### 2025-11-01 11:00 - Task Completed: Project Scaffolding
**Implementation:**
- Created complete source directory structure
- Created complete test directory structure
- Created all `__init__.py` files
- Created `src/npm_mcp/__main__.py` as entry point
- Created `tests/conftest.py` with shared fixtures
**Result:** ✅ Success - Complete project scaffolding established
### 2025-11-01 12:00 - Task Completed: Configuration Files
**Files Created:**
- `pyproject.toml` - Complete project configuration
- `pytest.ini` - Pytest configuration with coverage
- `.gitignore` - Updated to include .claude/ directory
- `CONTRIBUTING.md` - Development guide
**Result:** ✅ Success - All configuration complete
## Session Summary
### Completed
- [x] Project structure created
- [x] Configuration files set up
- [x] CLAUDE.md and phase documentation
- [x] Session management framework
- [x] Git repository initialized
### Metrics
- Files created: 25
- Lines of documentation: ~500
- Test framework: Ready
- Coverage: N/A (no code yet)
### Blockers
None encountered
### Decisions Made
1. Use structured markdown for session logs
2. Include .claude/ directory in version control
3. Use uv for Python environment management
4. Set 80% minimum coverage requirement
### Next Session Plan
**Objectives for Session 2:**
1. Implement configuration system (config/settings.py)
2. Write tests for configuration loading (ENV, YAML, validation)
3. Implement credential encryption
4. Target: 85%+ coverage for config module
**Context to Review:**
- PRD lines 100-150 (Configuration requirements)
- Phase 1 checklist
- This session summary
Notice the level of detail. Future sessions can pick up exactly where this left off.
The Decision Documentation Pattern
Every non-trivial decision gets documented like this:
### Decision Point: [Clear Title]
**Context:** [Why are we making this decision?]
**Options Considered:**
1. [Option A] - [Pros/Cons]
2. [Option B] - [Pros/Cons]
3. [Option C] - [Pros/Cons]
**Choice:** [Which option]
**Rationale:** [Why this choice makes sense]
**Impact:** [What this affects - dependencies, tests, timeline]
This creates a trail of why decisions were made, not just what was done.
When you (or Claude Code, or a teammate) look at this code in three months, the reasoning is right there. No archaeology required.
The Context Management Trick
Here’s a pattern that saves me hours every session:
Create .claude/next_session_plan.md:
# Next Session Plan
**Last Updated:** 2025-11-01 12:30
**Current Phase:** Phase 1 - Foundation
**Progress:** 10% (Day 1 of 10)
## Where We Are
Just completed Session 1:
- ✅ Project structure created
- ✅ Configuration files set up
- ✅ Documentation framework established
- ✅ Git repository initialized
Current test status: N/A (no code yet)
Current coverage: N/A (no code yet)
## What's Next (Session 2)
### Primary Objectives
1. Implement configuration system (settings.py)
2. Write comprehensive tests for config loading
3. Implement credential encryption with keyring
4. Target: 85%+ coverage for config module
### Specific Tasks
- [ ] Create `src/npm_mcp/config/settings.py`
- [ ] Write tests in `tests/unit/test_config/test_settings.py`
- [ ] Test ENV variable loading
- [ ] Test YAML file loading
- [ ] Test credential encryption/decryption
- [ ] Test validation with Pydantic
- [ ] Document configuration options
### Context to Review
- PRD lines 100-150 (Configuration requirements)
- Phase 1 day 1-3 checklist
- Session 1 summary (decisions made)
### Known Issues/Blockers
None currently
### Questions for User
None currently
At the start of every session, Claude Code reads this file and knows precisely where to pick up.
Session management documents are valid beyond giving Claude long-term memory.
- When you decide to add to your app, Claude can quickly understand how to do it.
- When you choose to run a threat modeling Claude Skill, it has the context.
- If you’re working with a team of developers, you can all stay in sync.
Pattern 4: Getting the Details Right
Let me show you some specific sections that make a huge difference:
Code Quality Standards
## Code Quality Standards
### Every Python File Must Include
- Module-level docstring with purpose and usage
- Complete type hints for all functions and methods
- Comprehensive docstrings (Google style)
- Error handling with specific exceptions
- Logging using `structlog` at appropriate levels
- Associated test file with minimum 80% coverage
### Code Style
- Follow PEP 8
- Use `ruff` for linting and formatting
- Use `mypy` for static type checking
- Maximum line length: 100 characters
- Meaningful variable names (no single letters except loop counters)
### Import Organization
```python
# Standard library imports
import asyncio
from typing import Optional
# Third-party imports
import httpx
from pydantic import BaseModel
# Local imports
from npm_mcp.auth.manager import AuthManager
Commit Standards## Git Commit Standards
### Conventional Commits Format
Types:
`feat:` for new features
`fix:` for bug fixes
`docs:` for documentation
`test:` for tests
`refactor:` for refactoring
`chore:` for maintenance
Example:
feat(auth): implement JWT token caching with refresh
- Add AuthManager class with token caching
- Implement automatic token refresh logic
- Add tests for token expiration scenarios
- Coverage: 95%
Refs: #12
Co-Authored-By: Claude <[email protected]>
## Commit Requirements
* One logical change per commit
* All tests passing before commit
* Include test updates with implementation
* Reference issue/ticket numbers when applicable
Error Handling Standards## Error Handling
### Custom Exception Hierarchy
Create project-specific exceptions in `exceptions.py`:
```python
class NPMError(Exception):
"""Base exception for NPM MCP."""
pass
class AuthenticationError(NPMError):
"""Authentication failed."""
pass
class ConfigurationError(NPMError):
"""Configuration is invalid."""
pass
Rules
* Never use bare `except:` clauses
* Log errors with context before re-raising
* Use `tenacity` for retry logic on transient errors
* Validate all external inputs
* Provide helpful error messages
If You Made It This Far
You’re a champ. This is a lot of dense information. Understanding the process's context is critical if you are going to apply it effectively.
Here’s the good news: Claude Code is great at doing it itself.
Here’s my process and resources to help you get going quickly:
- Write notes about the app you’re trying to build. Be specific about the features, functionality, and user stories you intend to tackle
- Ask Claude Code to write you a PRD and ask questions along the way
- Review the PRD
- Use my Claude Code project initialization skill
- Go
Tips and Tricks
Constantly remind Claude Code of what they should be doing:
Let’s start session 12, remember ALWAYS to follow TDD and protocols defined in @CLAUDE.MD
I need you to ensure that you have 80% test coverage with 100% pass rate. Do not stop until you’ve reached these metrics
I need you to review all requirements in the PRD, analyze the session and phase documentation, and produce a report of features that have not yet been fully implemented
What’s Next
You now have the foundation. The essential patterns that make AI-assisted development actually work:
- CLAUDE.md for clear direction
- TDD for built-in verification
- Phase-based development for a manageable scope
- Session management for context preservation
These four patterns address the most significant problems identified in Article 1.
But there’s more. Advanced patterns that take you from good to exceptional:
In Article 3, I’ll show you:
- Multi-agent orchestration (Test Designer → Implementation → Security Analyst)
- Reusable skill libraries (complex workflows you can invoke by name)
- Permission systems (pre-approve common operations, deny dangerous ones)
- Quality gates at every level (commit, phase, release)
- Continuous improvement (retrospectives and metrics that matter)
These patterns are what took my projects from 80% coverage to 90%+, from zero security issues to comprehensive security reviews, from good code to production-grade systems.
Check out my collection of Claude Code Skills and Agents.
