Organization patterns for AI-generated documentation
Note: AISD docs are generated by AI from human requirements, not hand-written. These patterns guide AI when structuring docs and help humans navigate AI-generated content.
Example references: Use model.md for illustration. In practice, use TypeScript/JSON Schema for models (authoritative), use AISD for business rules/constraints (AI-generated).
AI writes docs, AI reads docs, humans review diffs.
Optimize for:
- Context precision - AI loads exactly what's needed for the task
- Selective loading - Small files enable mixed context composition
- Single responsibility - One concept per file prevents over-loading
- No cascading dependencies - Self-contained files, no chain loading
- Index-based navigation - AI orients without reading full specs
docs/
├── index.md # System overview (<100 lines)
├── architecture.md # High-level design (200-500 lines)
├── domain-a/
│ ├── index.md # Domain overview (<100 lines)
│ ├── model.md # Entities (200-500 lines)
│ └── behavior.md # Operations (200-500 lines)
├── domain-b/
│ ├── index.md
│ ├── model.md
│ └── behavior.md
└── adr/
├── 0001-decision.md # Architectural Decision Record
└── 0002-decision.md
| Directory | Purpose | Contains |
|---|---|---|
docs/ |
Root documentation | index.md, architecture.md |
docs/domain-name/ |
Domain-specific docs | index.md, model.md, behavior.md |
docs/adr/ |
Architecture decisions | ADR files (numbered) |
Level 1: System (docs/index.md)
- System overview
- All domains listed
- High-level architecture
- <100 lines
Level 2: Domain (docs/domain/index.md)
- Domain purpose
- Entities listed
- Operations listed
- Links to specs
- <100 lines
Level 3: Specs (docs/domain/*.md)
- Full entity definitions (model.md)
- Complete operation specs (behavior.md)
- Integration details (integration.md)
- 200-500 lines each
# System Overview
**Purpose**: Task management system
## Domains
- **tasks/** - Core task entities and operations
- **users/** - User management and authentication
- **notifications/** - Notification delivery
## Architecture
See [architecture.md](architecture.md) for system design.# Tasks Domain
**Purpose**: Manage todo tasks with priorities
## Entities
- **Task** - Todo item with status and priority
## Operations
- **CreateTask** - Create new task
- **UpdateTaskStatus** - Change task status
- **GenerateDailyList** - Generate daily todo list
## Files
- **model.md** - Task entity definition
- **behavior.md** - Task operationsAI value:
- Without index: AI must read full spec files to understand domain scope
- With index: AI reads small index file, knows domain contents and which file to load
- Use case: "What domains exist?" → Load all index files instead of all specs
Purpose: Enable AI to load precise context without cascading dependencies
Not about: Architectural purity or project size
About: Context precision - AI loads exactly what's needed, nothing more
Domains MUST NOT directly reference entities from other domains.
❌ Bad (cross-domain coupling):
# User
| Field | Type |
|-------|------|
| id | UUID |
| orders | List[Order] | ← Direct reference to Order entityProblem: AI loading User entity must also load Order entity to understand type Cascade: User → Order → Product → Category → ... (context explosion)
✅ Good (primitive references):
# User
| Field | Type |
|-------|------|
| id | UUID |
| order_ids | List[UUID] | ← Primitive type onlyBenefit: User entity is self-contained, no cascade loading required
Use integration.md to document cross-domain relationships without coupling.
Example (docs/users/integration.md):
# User Integration
## Orders Integration
**Relationship**: User has many Orders (1:N)
**User side**:
- User has field: order_ids (List[UUID])
- User MUST NOT know Order internals
**Orders side**:
- Order has field: user_id (UUID)
- Order queries User via user_id
**API**: User service provides GetUserOrders(user_id) → List[UUID]Typical AI context windows: 8k-200k tokens
File size targets optimized for context:
- Index: <100 lines (~500 tokens)
- Spec: 200-500 lines (~1500-3000 tokens)
- Max: 1000 lines (~6000 tokens)
| Task | Load | Token Budget | Files Loaded |
|---|---|---|---|
| System overview | All indexes | ~2k | docs/*/index.md |
| Single domain work | One domain | ~4k | docs/domain/*.md |
| Cross-domain work | Two domains | ~8k | docs/domain-a/*.md, docs/domain-b/integration.md |
| Bug fix | Single spec | ~1.5k | docs/domain/behavior.md |
Task: Add "due dates" to tasks
Load:
docs/tasks/index.md(orientation)docs/tasks/model.md(see current fields)docs/tasks/behavior.md(see operations to update)
Don't load:
docs/users/*.md(not needed)docs/notifications/*.md(not needed)docs/architecture.md(too high-level)
Result: ~4k tokens, focused context
Task: Send notification when task is created
Load:
docs/tasks/behavior.md(CreateTask operation)docs/notifications/behavior.md(SendNotification operation)docs/tasks/integration.md(how tasks trigger notifications)
Don't load:
docs/tasks/model.md(already know Task structure)docs/users/*.md(not relevant)
Result: ~6k tokens, relevant context only
Not about project size - about context precision
Wrong question: "Is my project big enough to need split files?" Right question: "Will AI need to load these concepts together or separately?"
Split when:
- Concepts used independently (User vs Role vs Permission - load separately)
- File exceeds 500 lines
- AI would over-load context for simple tasks
Keep together when:
- Concepts always used together (Cart + CartItem + Checkout - always co-loaded)
- Total <500 lines
- Splitting creates no context loading benefit
How to split:
By domain:
before: tasks-and-users-model.md (800 lines)
after: tasks/model.md (400 lines)
users/model.md (400 lines)
By concern:
before: tasks/model.md (700 lines with validation rules)
after: tasks/model.md (350 lines - just entities)
tasks/validation.md (350 lines - validation rules)
By operation:
before: tasks/behavior.md (900 lines - all operations)
after: tasks/create-operations.md (300 lines)
tasks/update-operations.md (300 lines)
tasks/query-operations.md (300 lines)
Example 1: Split files enable selective loading
Task: "Add due dates to tasks"
Large file approach:
docs/model.md (all entities in one file)
AI loads: Entire file including User, Task, Tag, Comment, Attachment
Small file approach:
docs/tasks/model.md
AI loads: Only Task entity
Example 2: Mixed context composition
Task: "Send notification when task assigned to user"
Load:
tasks/model.md(task fields)users/behavior.md(how to notify)notifications/behavior.md(notification operations)
Don't load:
users/model.md(don't need user fields)tasks/behavior.md(not creating tasks)- Tag, Comment, Attachment files
This precise mixing impossible with multi-responsibility files
Use bold filename followed by description.
## Related
- **model.md** - Task entity definitions
- **behavior.md** - Task operations
- **../users/model.md** - User entity definitionsBenefits:
- Scannable
- Works well in AI-generated lists
- Clear relationship to file structure
Use for prose references.
See [model.md](model.md) for Task entity fields.
Integration with users documented in [../users/integration.md](../users/integration.md).Within same directory:
[model.md](model.md)Parent directory:
[../index.md](../index.md)Sibling directory:
[../users/model.md](../users/model.md)Never use absolute paths:
❌ [/docs/users/model.md](/docs/users/model.md)
✅ [../users/model.md](../users/model.md)1. Monolithic files:
docs/
└── everything.md (3000 lines)
Why bad: Exceeds context limits, mixes concerns, hard to navigate
2. No hierarchy:
docs/
├── task-entity.md
├── user-entity.md
├── create-task.md
├── update-task.md
├── create-user.md
└── login-user.md
Why bad: Flat structure, no domain isolation, hard to find related files
3. Cross-domain coupling:
# User (in docs/users/model.md)
| Field | Type |
|-------|------|
| current_task | Task | ← Directly references Task entityWhy bad: Domains tightly coupled, can't load users without tasks
4. Implementation in specs:
# CreateTask
Store task in PostgreSQL using SQLAlchemy ORM.
Use connection pool with max 10 connections.Why bad: Spec should describe behavior, not implementation
1. Hierarchical structure:
docs/
├── index.md
├── tasks/
│ ├── index.md
│ ├── model.md
│ └── behavior.md
└── users/
├── index.md
├── model.md
└── behavior.md
2. Domain isolation with integration:
# User (in docs/users/model.md)
| Field | Type |
|-------|------|
| task_ids | List[UUID] | ← Primitive reference only
# Integration (in docs/users/integration.md)
User has many Tasks via task_ids3. Behavior-only specs:
# CreateTask
**Preconditions**: Title MUST be 1-200 characters
**Actions**:
1. Generate UUID
2. Set status to "pending"
3. Store task persistently
**Postconditions**: Task persists across application restarts# Check for index.md in each domain directory
for dir in docs/*/; do
if [ ! -f "$dir/index.md" ]; then
echo "Missing index.md in $dir"
fi
done# Find files exceeding 500 lines
wc -l docs/**/*.md | awk '$1 > 500 {print $2 ": " $1 " lines (max 500)"}'# Check for broken markdown links (requires markdown-link-check)
find docs/ -name "*.md" -exec markdown-link-check {} \;Directory structure:
docs/
├── index.md (<100 lines)
├── domain-name/
│ ├── index.md (<100 lines)
│ ├── model.md (200-500 lines)
│ └── behavior.md (200-500 lines)
File sizes:
- Index: <100 lines
- Spec: 200-500 lines
- Max: 1000 lines (split if exceeded)
Domain isolation:
- Use primitive types (UUID, String) for cross-domain references
- Use integration.md to document domain bridges
- Never directly reference entities from other domains
Context loading:
- System overview: Load all indexes (~2k tokens)
- Single domain: Load one domain (~4k tokens)
- Integration: Load 2-3 domains (~8k tokens)
- README.md - Overview of AISD documentation standard
- style-guide.md - Writing rules
- templates/ - Document templates
Back to: README.md for standard overview.